diff --git a/.github/Dockerfile b/.github/Dockerfile index 2c4e3c46..a1c65ad4 100644 --- a/.github/Dockerfile +++ b/.github/Dockerfile @@ -20,8 +20,8 @@ RUN apt-get update && \ ruby-coderay \ gcc-arm-linux-gnueabi \ libc6-dev-armel-cross \ - qemu-system-arm \ qemu-system-misc \ + qemu-system-arm \ black \ python3-pip \ python3-serial \ @@ -35,8 +35,3 @@ RUN apt-get update && \ icnsutils \ black && \ pip3 install --break-system-packages pynsist - -RUN mkdir snek -COPY ./ snek/ - -WORKDIR ./snek diff --git a/.github/workflows/snek.yml b/.github/workflows/snek.yml index 7abfe8ee..f432e0f8 100644 --- a/.github/workflows/snek.yml +++ b/.github/workflows/snek.yml @@ -70,16 +70,20 @@ jobs: docker load -i $IMAGE_FILE docker images -a $IMAGE - - name: 'Create install destinationn' + - name: 'Create install destination' run: | - mkdir `pwd`/artifacts + mkdir -p artifacts - name: 'Build snek' run: | - docker run --rm \ - --mount type=bind,source=`pwd`/artifacts,destination=/artifacts \ - snek \ - make DESTDIR=/artifacts PREFIX=/opt/snek SNEK_OTHEROS=1 SNEK_RISCV_TEST=1 black check install install-otheros + docker run \ + -v $(readlink -f snek):/snek \ + -v $(readlink -f artifacts):/artifacts \ + -w /snek \ + $IMAGE \ + make DESTDIR=/artifacts PREFIX=/opt/snek SNEK_OTHEROS=1 \ + SNEK_RISCV_TEST=1 -j$(nproc) \ + black check install install-otheros - name: 'Upload results' uses: actions/upload-artifact@v4 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..3f08e2ff --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "ubaboot"] + path = ubaboot + url = https://github.com/keith-packard/ubaboot.git diff --git a/Makefile b/Makefile index 9187247f..79ec7e6a 100644 --- a/Makefile +++ b/Makefile @@ -35,10 +35,10 @@ check: all +cd test && make $@ black: - +black --check --exclude 'fail-syntax-.*\.py|.*/hosts/.*.py' . + +black --check --exclude 'fail-syntax-.*\.py|.*/hosts/.*.py|ubaboot.py' . black-reformat: - +black --exclude 'fail-syntax-.*\.py|.*/hosts/.*.py' . + +black --exclude 'fail-syntax-.*\.py|.*/hosts/.*.py|ubaboot.py' . install: all +for dir in $(SUBDIRS); do (cd $$dir && make PREFIX=$(PREFIX) DESTDIR=$(DESTDIR) $@) || exit 1; done @@ -46,13 +46,13 @@ install: all upload: otheros +cd doc && make upload - +for otheros in $(SNEK_OTHEROS_DIR); do (cd "$$otheros" && make upload); done + +for otheros in $(SNEK_OTHEROS_DIR); do (cd "$$otheros" && make upload) || exit 1; done install-otheros: otheros install - +for otheros in $(SNEK_OTHEROS_DIR); do (cd "$$otheros" && make install-otheros); done + +for otheros in $(SNEK_OTHEROS_DIR); do (cd "$$otheros" && make install-otheros) || exit 1; done otheros: all - +for otheros in $(SNEK_OTHEROS_DIR); do (cd "$$otheros" && make); done + +for otheros in $(SNEK_OTHEROS_DIR); do (cd "$$otheros" && make) || exit 1; done snek-mu.py: find . -name '*.builtin' -print0 | xargs -0 python3 ./snek-builtin.py --mu -o $@ diff --git a/ao/ao-product.c b/ao/ao-product.c index 0c1da752..714198bd 100644 --- a/ao/ao-product.c +++ b/ao/ao-product.c @@ -57,7 +57,7 @@ #define NUM_INTERFACES (AO_USB_HAS_INT + 1) /* USB descriptors in one giant block of bytes */ -const uint8_t ao_usb_descriptors [] = +CONST uint8_t ao_usb_descriptors [] = { /* Device descriptor */ 0x12, diff --git a/ao/ao-usb.h b/ao/ao-usb.h index 733537cf..4706a706 100644 --- a/ao/ao-usb.h +++ b/ao/ao-usb.h @@ -52,7 +52,7 @@ ao_usb_disable(void); void ao_usb_init(void); -extern const uint8_t ao_usb_descriptors []; +extern CONST uint8_t ao_usb_descriptors []; #define AO_USB_SETUP_DIR_MASK (0x01 << 7) #define AO_USB_SETUP_TYPE_MASK (0x03 << 5) @@ -159,8 +159,6 @@ struct ao_usb_line_coding { uint8_t data_bits; } ; -extern struct ao_usb_line_coding ao_usb_line_coding; - extern uint8_t ao_usb_running; #endif /* _AO_USB_H_ */ diff --git a/chips/atmega/snek-328p.builtin b/chips/atmega/snek-328p.builtin index 8d0a8609..b32005d3 100644 --- a/chips/atmega/snek-328p.builtin +++ b/chips/atmega/snek-328p.builtin @@ -34,10 +34,10 @@ A4, -2, 18 A5, -2, 19 #include #if !defined(SNEK_POOL) -#define SNEK_POOL 900 +#define SNEK_POOL 1024 #endif #define SNEK_MAX_TOKEN 63 -#define VALUE_STACK_SIZE 16 +#define VALUE_STACK_SIZE 32 #ifndef PARSE_STACK_SIZE #define PARSE_STACK_SIZE 128 #endif diff --git a/chips/atmega/snek-328p.c b/chips/atmega/snek-328p.c index aff176df..2e38f7c6 100644 --- a/chips/atmega/snek-328p.c +++ b/chips/atmega/snek-328p.c @@ -181,7 +181,7 @@ has_pwm(uint8_t p) return pwm_pins & (1 << p); } -static volatile uint8_t * const PROGMEM ocr_reg_addrs[] = { +static volatile uint8_t * CONST ocr_reg_addrs[] = { [3] = &OCR2B, [5] = &OCR0B, [6] = &OCR0A, @@ -192,10 +192,10 @@ static volatile uint8_t * const PROGMEM ocr_reg_addrs[] = { static volatile uint8_t * ocr_reg(uint8_t pin) { - return (volatile uint8_t *) pgm_read_word(&ocr_reg_addrs[pin]); + return ocr_reg_addrs[pin]; } -static volatile uint8_t * const PROGMEM tcc_reg_addrs[] = { +static volatile uint8_t * CONST tcc_reg_addrs[] = { [3] = &TCCR2A, [5] = &TCCR0A, [6] = &TCCR0A, @@ -206,10 +206,10 @@ static volatile uint8_t * const PROGMEM tcc_reg_addrs[] = { static volatile uint8_t * tcc_reg(uint8_t pin) { - return (volatile uint8_t *) pgm_read_word(&tcc_reg_addrs[pin]); + return tcc_reg_addrs[pin]; } -static uint8_t const PROGMEM tcc_val_addrs[] = { +static uint8_t CONST tcc_val_addrs[] = { [3] = 1 << COM2B1, [5] = 1 << COM0B1, [6] = 1 << COM0A1, @@ -221,7 +221,7 @@ static uint8_t const PROGMEM tcc_val_addrs[] = { static uint8_t tcc_val(uint8_t pin) { - return (uint8_t) pgm_read_byte(&tcc_val_addrs[pin]); + return tcc_val_addrs[pin]; } static void @@ -381,6 +381,7 @@ snek_poly_t snek_builtin_setpower(snek_poly_t a) { float p = snek_poly_get_float(a); + printf("%p\n", &p); if (p < 0.0f) p = 0.0f; if (p > 1.0f) p = 1.0f; power[power_pin] = (uint8_t) (p * 255.0f + 0.5f); diff --git a/chips/atmega/snek-atmega-eeprom.c b/chips/atmega/snek-atmega-eeprom.c index 7212202d..e9e66770 100644 --- a/chips/atmega/snek-atmega-eeprom.c +++ b/chips/atmega/snek-atmega-eeprom.c @@ -16,6 +16,10 @@ #include "snek-io.h" #include +#ifndef EEPROM_SIZE +#define EEPROM_SIZE (E2END + 1) +#endif + snek_poly_t snek_builtin_eeprom_write(void) { @@ -28,7 +32,7 @@ snek_builtin_eeprom_write(void) c = 0xff; eeprom_write_byte((uint8_t *) addr, c); addr++; - if (addr == (E2END + 1)) + if (addr == EEPROM_SIZE) break; if (c == 0xff) break; @@ -46,7 +50,7 @@ snek_builtin_eeprom_show(uint8_t nposition, uint8_t nnamed, snek_poly_t *args) (void) args; if (nposition) putc('b' & 0x1f, stdout); - for (addr = 0; addr <= E2END; addr++) { + for (addr = 0; addr < EEPROM_SIZE; addr++) { c = eeprom_read_byte((uint8_t *) addr); if (c == 0xff) break; @@ -71,7 +75,7 @@ int snek_eeprom_getchar(FILE *stream) { (void) stream; - if (snek_eeprom_addr <= E2END && !snek_abort) { + if (snek_eeprom_addr < EEPROM_SIZE && !snek_abort) { uint8_t c = eeprom_read_byte((uint8_t *) (snek_eeprom_addr++)); if (c != 0xff) return c; diff --git a/chips/atmega/snek-atmega-flash.c b/chips/atmega/snek-atmega-flash.c new file mode 100644 index 00000000..939df6a4 --- /dev/null +++ b/chips/atmega/snek-atmega-flash.c @@ -0,0 +1,187 @@ +/* + * Copyright © 2024 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "snek.h" +#include "snek-io.h" +#include +#include + +static uint8_t *flash_write_addr; +static bool flash_write_page_pending; + +static inline uint8_t * +flash_start(void) +{ + uint8_t append = FUSE_APPEND; + + if (append == 0) + return NULL; + return (uint8_t *) (MAPPED_PROGMEM_START + append * 256); +} + +static inline uint8_t * +flash_end(void) +{ + return (uint8_t *) MAPPED_PROGMEM_END; +} + +static inline ptrdiff_t +flash_size(void) +{ + uint8_t *start = flash_start(); + if (!start) + return 0; + return (flash_end() - start) + 1; +} + +static inline bool +flash_start_of_page(uint8_t *addr) { + return ((uintptr_t) addr & (PROGMEM_PAGE_SIZE - 1)) == 0; +} + +static inline bool +flash_end_of_page(uint8_t *addr) { + return (((uintptr_t) addr + 1) & (PROGMEM_PAGE_SIZE - 1)) == 0; +} + +static inline uint8_t * +flash_page_addr(uint8_t *addr) { + return (uint8_t *) ((uintptr_t) addr & ~(PROGMEM_PAGE_SIZE - 1)); +} + +static bool +flash_write_full(void) +{ + return flash_write_addr == flash_end(); +} + +static void +flash_cmd(uint8_t cmd) +{ + while (NVMCTRL.STATUS & (NVMCTRL_FBUSY_bm|NVMCTRL_EEBUSY_bm)); + _PROTECTED_WRITE_SPM(NVMCTRL.CTRLA, cmd); + while (NVMCTRL.STATUS & (NVMCTRL_FBUSY_bm|NVMCTRL_EEBUSY_bm)); +} + +static void +flash_write_init(void) +{ + flash_write_addr = flash_start(); + flash_write_page_pending = false; + flash_cmd(NVMCTRL_CMD_PAGEBUFCLR_gc); +} + +static void +flash_write_flush(void) +{ + if (flash_write_page_pending) { + flash_write_page_pending = false; + /* + * Wait for an ENQ to appear in the input buffer. Once + * that is there, the sender will stop transmitting + * until we reply with an ACK, and that won't happen + * until we read the ENQ from the input buffer, so we + * can safely stop the CPU while writing flash without + * dropping any incoming data. Give up if not seen within + * a few dozen ms; that will happen when the sender is + * done sending commands. + */ + snek_uart_wait_queued('e' & 0x1f, U_TICKS_PER_SECOND / 16); + flash_cmd(NVMCTRL_CMD_PAGEERASEWRITE_gc); + } +} + +static void +flash_write_byte(uint8_t byte) +{ + *flash_write_addr = byte; + flash_write_page_pending = true; + if (flash_end_of_page(flash_write_addr)) + flash_write_flush(); + flash_write_addr++; +} + +static uint8_t +flash_read_byte(uint8_t *addr) +{ + return *addr; +} + +snek_poly_t +snek_builtin_eeprom_write(void) +{ + uint8_t c; + + flash_write_init(); + for(;;) { + c = snek_raw_getc(stdin); + if (c == ('d' & 0x1f)) + c = 0xff; + flash_write_byte(c); + if (flash_write_full()) + break; + if (c == 0xff) + break; + } + flash_write_flush(); + return SNEK_NULL; +} + +snek_poly_t +snek_builtin_eeprom_show(uint8_t nposition, uint8_t nnamed, snek_poly_t *args) +{ + uint8_t c; + uint8_t *addr; + + (void) nnamed; + (void) args; + if (nposition) + putc('b' & 0x1f, stdout); + for (addr = flash_start(); addr <= flash_end(); addr++) { + c = flash_read_byte(addr); + if (c == 0xff) + break; + putc(c, stdout); + } + if (nposition) + putc('c' & 0x1f, stdout); + return SNEK_NULL; +} + +snek_poly_t +snek_builtin_eeprom_erase(void) +{ + if (flash_read_byte(0) != 0xff) { + flash_write_init(); + flash_write_byte(0xff); + flash_write_flush(); + } + return SNEK_NULL; +} + +static ptrdiff_t snek_flash_off; + +int +snek_eeprom_getchar(FILE *stream) +{ + (void) stream; + if (snek_flash_off < flash_size() && !snek_abort) { + uint8_t c = flash_read_byte(flash_start() + snek_flash_off++); + if (c != 0xff) + return c; + } + snek_interactive = true; + snek_duino_file.get = snek_io_getc; + return EOF; +} diff --git a/chips/atmega/snek-atmega-math.h b/chips/atmega/snek-atmega-math.h index 4bc5d461..61cee920 100644 --- a/chips/atmega/snek-atmega-math.h +++ b/chips/atmega/snek-atmega-math.h @@ -19,6 +19,8 @@ #ifndef _SNEK_MEGA_MATH_H_ #define _SNEK_MEGA_MATH_H_ +#undef float + float exp2f(float x); float expm1f(float x); diff --git a/chips/atmega/snek-atmega-serial.c b/chips/atmega/snek-atmega-serial.c index 6fb5ab03..b9df14c3 100644 --- a/chips/atmega/snek-atmega-serial.c +++ b/chips/atmega/snek-atmega-serial.c @@ -168,6 +168,7 @@ ISR(RX_vect) switch (c) { case 'c' & 0x1f: snek_abort = true; + rx_ring.count = 0; break; case 's' & 0x1f: tx_flow = true; @@ -231,18 +232,56 @@ snek_uart_putchar(char c, FILE *stream) } void -_snek_uart_puts(const char *PROGMEM string) +_snek_uart_puts(CONST char *string) { char c; - while ((c = pgm_read_byte(string++))) + while ((c = *string++)) snek_uart_putch(c); } +#ifdef SNEK_NEED_UART_WAIT_QUEUED +void +snek_uart_wait_queued(char c, uint32_t ticks) +{ + int ret = 0; + uint8_t count; + uint32_t end_tick = snek_ticks() + ticks; + + for (;;) { + cli(); + for (count = 0; count < rx_ring.count; count++) { + uint8_t pos = (rx_ring.read + count) & (UART_RINGSIZE - 1); + if (rx_ring.buf[pos] == c) { + ret = 1; + break; + } + } + sei(); + if (ret) + return; + if (((int32_t) (snek_ticks() - end_tick)) >= 0) + return; + } +} +#endif + void snek_uart_init(void) { #if defined(__AVR_ATmega4809__) - PORTMUX.USARTROUTEA |= PORTMUX_USART30_bm; +#ifndef USART_CHSIZE_0_bm +#define USART_CHSIZE_0_bm USART_CHSIZE0_bm +#endif + +#ifndef USART_CHSIZE_1_bm +#define USART_CHSIZE_1_bm USART_CHSIZE1_bm +#endif + +#ifndef PORTMUX_USART3_0_bm +#define PORTMUX_USART3_0_bm PORTMUX_USART30_bm +#endif + + PORTMUX.USARTROUTEA |= PORTMUX_USART3_0_bm; int32_t baud_setting; baud_setting = (((8 * F_CPU) / UART_BAUD) + 1) / 2; @@ -250,7 +289,7 @@ snek_uart_init(void) baud_setting += (baud_setting * sigrow_val) / 1024; USART3.BAUD = baud_setting; - USART3.CTRLC = (USART_CHSIZE0_bm | USART_CHSIZE1_bm); + USART3.CTRLC = (USART_CHSIZE_0_bm | USART_CHSIZE_1_bm); VPORTB_DIR |= (1 << 4); VPORTB_OUT |= (1 << 4); USART3.CTRLB = (USART_RXEN_bm | diff --git a/chips/atmega/snek-atmega-time.c b/chips/atmega/snek-atmega-time.c index e87a67f6..4bf267b8 100644 --- a/chips/atmega/snek-atmega-time.c +++ b/chips/atmega/snek-atmega-time.c @@ -46,8 +46,7 @@ ISR(timer_vect) timer_tocks++; } - -static uint32_t +uint32_t snek_ticks(void) { uint32_t tocks_before, tocks_after; diff --git a/chips/atmega/snek-atmega.defs b/chips/atmega/snek-atmega.defs index 59dd411e..df2733db 100644 --- a/chips/atmega/snek-atmega.defs +++ b/chips/atmega/snek-atmega.defs @@ -12,6 +12,8 @@ # General Public License for more details. # +vpath strfromg.c $(SNEK_ATMEGA)/../avr + SNEK_ATMEGA_MATH_SRC = \ snek-math.c \ ef_remainder.c \ @@ -29,8 +31,12 @@ SNEK_ATMEGA_MATH_SRC = \ kf_sin.c \ kf_cos.c +SNEK_ATMEGA_STORE_SRC ?= snek-atmega-eeprom.c + SNEK_ATMEGA_SRC = \ - snek-atmega-eeprom.c \ + strfromg.c \ + $(SNEK_ATMEGA_STORE_SRC) \ + snek-input.c \ snek-io.c \ snek-atof.c \ snek-random-small.c \ @@ -52,7 +58,21 @@ SNEK_ATMEGA_MATH_BUILTINS = \ SNEK_ATMEGA_BUILTINS = \ snek-eeprom.builtin \ snek-gpio.builtin \ + snek-input.builtin \ snek-random.builtin \ snek-atmega.builtin SNEK_NO_FILE = 1 + +OPT=-Os \ + -mrelax \ + -Wno-array-bounds \ + -frename-registers \ + -funsigned-char \ + -mcall-prologues \ + -fno-move-loop-invariants \ + -fno-move-loop-stores \ + -fno-split-loops \ + -fno-unswitch-loops \ + -fno-unroll-loops \ + -fno-peel-loops diff --git a/chips/atmega/snek-atmega.h b/chips/atmega/snek-atmega.h index 37400cf2..f987f16d 100644 --- a/chips/atmega/snek-atmega.h +++ b/chips/atmega/snek-atmega.h @@ -21,88 +21,75 @@ #include #define SNEK_DEBUG 0 -float atoff(const char *); -#define strtof(s, n) atoff(s) -#define PARSE_TABLE_DECLARATION(t) PROGMEM t -#define PARSE_TABLE_FETCH_TOKEN(a) ((token_key_t) pgm_read_byte(a)) -#define PARSE_TABLE_FETCH_INDEX(a) ((uint8_t) pgm_read_byte(a)) -#define ERROR_FETCH_FORMAT_CHAR(a) ((char) pgm_read_byte(a)) -/* no sense linking both functions */ -#define memcpy(a,b,c) memmove(a,b,c) +#ifdef __AVR_PM_BASE_ADDRESS__ +#define CONST const +#else +#define PARSE_TABLE_DECLARATION(t) __flash t +#define CONST const __flash #define snek_error_name snek_internal_error #define snek_error(fmt, args...) ({ \ - static const char PROGMEM __fmt__[] = (fmt); \ + static CONST char __fmt__[] = (fmt); \ snek_internal_error(__fmt__, ## args); \ }) #define snek_error_0_name snek_internal_error_0 #define snek_error_0(string) ({ \ - static const char PROGMEM __string__[] = (string); \ + static CONST char __string__[] = (string); \ snek_internal_error_0(__string__); \ }) #define fprintf(file, fmt, args...) ({ \ - static const char PROGMEM __fmt__[] = (fmt); \ - printf_P(__fmt__, ## args); \ + static CONST char __fmt__[] = (fmt); \ + printf_P((const char *) (uintptr_t) __fmt__, ## args); \ }) -#define sprintf_const(dst, fmt, args...) ({ \ - static const char PROGMEM __fmt__[] = (fmt); \ - sprintf_P(dst, __fmt__, ##args); \ +#define sprintf_const(dst, fmt, args...) ({ \ + static CONST char __fmt__[] = (fmt); \ + sprintf_P(dst, (const char *) (uintptr_t) __fmt__, ##args); \ + }) + +#define trailing(next, wo_op, wo, w_op, w) ({ \ + static CONST char __next__[] = (next); \ + trailing_internal(__next__, wo_op, wo, w_op, w); \ + }) +#define trailing_name trailing_internal + + +#define snek_const_strcmp(a,b) strcmp_P(a,(const char *) (uintptr_t) (b)) + +#define snek_const_strcpy(a,b) ({ \ + static CONST char __str__[] = (b); \ + strcpy_P(a, (const char *) (uintptr_t) (__str__)); \ }) -#define strfromf_const(dst, len, fmt, val) sprintf_const(dst, fmt, val) -#define strfromf(dst, len, fmt, val) sprintf(dst, fmt, val) - -#define SNEK_BUILTIN_NAMES_DECLARE(n) PROGMEM n -#define SNEK_BUILTIN_NAMES(a) ((uint8_t) pgm_read_byte(&snek_builtin_names[a])) -#define SNEK_BUILTIN_NAMES_CMP(a,b) strcmp_P(a,b) - -#define SNEK_BUILTIN_DECLARE(n) PROGMEM n -#define SNEK_BUILTIN_NFORMAL(b) ((int8_t) pgm_read_byte(&(b)->nformal)) -#define SNEK_BUILTIN_FUNCV(b) ((snek_poly_t(*)(uint8_t, uint8_t, snek_poly_t *)) pgm_read_ptr(&(b)->funcv)) -#define SNEK_BUILTIN_FUNC0(b) ((snek_poly_t(*)(void)) pgm_read_ptr(&(b)->func0)) -#define SNEK_BUILTIN_FUNC1(b) ((snek_poly_t(*)(snek_poly_t)) pgm_read_ptr(&(b)->func1)) -#define SNEK_BUILTIN_FUNC2(b) ((snek_poly_t(*)(snek_poly_t, snek_poly_t)) pgm_read_ptr(&(b)->func2)) -#define SNEK_BUILTIN_FUNC3(b) ((snek_poly_t(*)(snek_poly_t, snek_poly_t, snek_poly_t)) pgm_read_ptr(&(b)->func3)) -#define SNEK_BUILTIN_FUNC4(b) ((snek_poly_t(*)(snek_poly_t, snek_poly_t, snek_poly_t, snek_poly_t)) pgm_read_ptr(&(b)->func4)) -#define SNEK_BUILTIN_VALUE(b) ((snek_poly_t)(uint32_t)pgm_read_dword(&(b)->value)) - -#define SNEK_ROOT_DECLARE(n) PROGMEM n -#define SNEK_ROOT_TYPE(n) ((const snek_mem_t *) pgm_read_ptr(&(n)->type)) -#define SNEK_ROOT_ADDR(n) ((void **) pgm_read_ptr(&(n)->addr)) static inline const char * -avr_snek_builtin_names_return(const uint8_t *bits) +avr_snek_builtin_names_return(CONST uint8_t *bits) { static char ret[SNEK_BUILTIN_NAMES_MAX_LEN + 1]; - char *r = ret; - while ((*r++ = (char) pgm_read_byte(bits++))) - ; - return ret; + return strcpy_P(ret, (const char *) (uintptr_t) bits); } -static inline int -avr_snek_builtin_names_len(const char *a) -{ - int len = 0; +#define snek_builtin_names_return(a) avr_snek_builtin_names_return(a) +#define snek_builtin_names_len(a) strnlen_P((const char *) (uintptr_t) (a), SNEK_BUILTIN_NAMES_MAX_LEN+1) - while (pgm_read_byte(a++)) - len++; - return len; -} +//#define strfromf_const(dst, len, fmt, val) sprintf_const(dst, fmt, val) +//#define strfromf(dst, len, fmt, val) sprintf(dst, fmt, val) +#endif /* !__AVR_PM_BASE_ADDRESS__ */ -#define snek_builtin_names_return(a) avr_snek_builtin_names_return(a) -#define snek_builtin_names_len(a) avr_snek_builtin_names_len(a) +float atoff(const char *); +#define strtof(s, n) atoff(s) + +/* no sense linking both functions */ +#define memcpy(a,b,c) memmove(a,b,c) +#define printf(a,args...) fprintf(stdout, a, ##args) -#define SNEK_MEM_DECLARE(n) PROGMEM n -#define SNEK_MEM_SIZE(m) ((snek_offset_t (*)(void *addr)) pgm_read_word(&(m)->size)) -#define SNEK_MEM_MARK(m) ((void (*)(void *addr)) pgm_read_ptr(&(m)->mark)) -#define SNEK_MEM_MOVE(m) ((void (*)(void *addr)) pgm_read_ptr(&(m)->move)) +int +strfromg(char *dst0, float val); -#define SNEK_MEMS_DECLARE(n) PROGMEM n +#define strfromf(dst, len, fmt, val) strfromg(dst, val) void snek_uart_init(void); @@ -116,16 +103,27 @@ snek_uart_getchar(FILE *stream); int snek_eeprom_getchar(FILE *stream); +#define TICKS_PER_SECOND (F_CPU / 64.0f) +#define SECONDS_PER_TICK (64.0f / F_CPU) + +#define U_TICKS_PER_SECOND (F_CPU / 64) + +uint32_t +snek_ticks(void); + char snek_uart_getch(void); void -_snek_uart_puts(const char *PROGMEM string); +_snek_uart_puts(CONST char *string); void snek_uart_putch(char c); -#define snek_uart_puts(string) ({ static const char PROGMEM __string__[] = (string); _snek_uart_puts(__string__); }) +void +snek_uart_wait_queued(char c, uint32_t ticks); + +#define snek_uart_puts(string) ({ static CONST char __string__[] = (string); _snek_uart_puts(__string__); }) #define SNEK_IO_PUTS(s) snek_uart_puts(s) #define SNEK_IO_LINEBUF 80 diff --git a/chips/avr/Makefile b/chips/avr/Makefile new file mode 100644 index 00000000..7223cd7c --- /dev/null +++ b/chips/avr/Makefile @@ -0,0 +1,5 @@ +strfromg-test: strfromg.c ftoa_engine.c strfromg-test.c + gcc -DSTRFROMG_TEST -O2 -o $@ -g strfromg.c strfromg-test.c ftoa_engine.c + +clean: + rm -f strfromg-test diff --git a/chips/avr/ao-arch.h b/chips/avr/ao-arch.h index e20307aa..15ef4ac7 100644 --- a/chips/avr/ao-arch.h +++ b/chips/avr/ao-arch.h @@ -24,6 +24,10 @@ #include #include +#ifndef CONST +#define CONST const __flash +#endif + /* * AVR definitions and code fragments for AltOS */ diff --git a/chips/avr/ao-snek-avr.c b/chips/avr/ao-snek-avr.c index 627e0575..db151ff1 100644 --- a/chips/avr/ao-snek-avr.c +++ b/chips/avr/ao-snek-avr.c @@ -186,16 +186,16 @@ main (void) snek_parse(); } -static const PROGMEM uint8_t _pin_map[NUM_PIN] = PIN_MAP; -static const PROGMEM uint8_t _adc_map[NUM_ADC] = ADC_MAP; -static uint8_t const PROGMEM ocr_reg_addrs[NUM_PIN] = OCR_REG_ADDRS; -static volatile uint8_t const PROGMEM tcc_reg_addrs[] = TCC_REG_ADDRS; -static uint8_t const PROGMEM tcc_reg_vals[] = TCC_REG_VALS; +static CONST uint8_t _pin_map[NUM_PIN] = PIN_MAP; +static CONST uint8_t _adc_map[NUM_ADC] = ADC_MAP; +static CONST uint8_t ocr_reg_addrs[NUM_PIN] = OCR_REG_ADDRS; +static CONST uint8_t tcc_reg_addrs[] = TCC_REG_ADDRS; +static CONST uint8_t tcc_reg_vals[] = TCC_REG_VALS; -static uint8_t +static inline uint8_t pin_map(uint8_t pin) { - return pgm_read_byte(&_pin_map[pin]); + return _pin_map[pin]; } static volatile uint8_t * @@ -230,7 +230,7 @@ has_adc(uint8_t p) static volatile uint8_t * ocr_reg(uint8_t pin) { - return (volatile uint8_t *) (uintptr_t) pgm_read_byte(&ocr_reg_addrs[pin]); + return (volatile uint8_t *) (uintptr_t) ocr_reg_addrs[pin]; } static bool @@ -241,14 +241,14 @@ has_pwm(uint8_t p) static volatile uint8_t * tcc_reg(uint8_t pin) { - return (volatile uint8_t *) (uintptr_t) pgm_read_byte(&tcc_reg_addrs[pin]); + return (volatile uint8_t *) (uintptr_t) tcc_reg_addrs[pin]; } static uint8_t tcc_reg_val(uint8_t pin) { - return (uint8_t) pgm_read_byte(&tcc_reg_vals[pin]); + return tcc_reg_vals[pin]; } static void @@ -416,7 +416,7 @@ snek_builtin_read(snek_poly_t a) set_dir(p, 0); if (has_adc(p) && !pull[p]) { - uint8_t pin = pgm_read_byte(&_adc_map[p - FIRST_ADC]); + uint8_t pin = _adc_map[p - FIRST_ADC]; ADMUX = (analog_reference << REFS0) | (pin & 7); ADCSRA |= (1 << ADSC); while (ADCSRA & (1 << ADSC)) @@ -505,5 +505,5 @@ snek_builtin_reset(void) /* and off we go! */ longjmp(snek_reset_buf, 1); - return SNEK_NULL; + __builtin_unreachable(); } diff --git a/chips/avr/ao-usb-avr.c b/chips/avr/ao-usb-avr.c index fcd2c6c7..329a931c 100644 --- a/chips/avr/ao-usb-avr.c +++ b/chips/avr/ao-usb-avr.c @@ -30,11 +30,10 @@ struct ao_usb_setup { static struct ao_fifo ao_usb_rx_fifo; -static const uint8_t * ao_usb_ep0_in_data; +static CONST uint8_t * ao_usb_ep0_in_data; static uint8_t ao_usb_ep0_in_len; static bool ao_usb_ep0_in_pending; static uint8_t ao_usb_address; -static uint8_t ao_usb_ep0_in_buf[2]; static uint8_t ao_usb_ep0_out_len; static uint8_t *ao_usb_ep0_out_data; @@ -119,14 +118,14 @@ ISR(USB_GEN_vect) } -struct ao_usb_line_coding ao_usb_line_coding = {115200, 0, 0, 8}; +static CONST struct ao_usb_line_coding ao_usb_line_coding = {115200, 0, 0, 8}; /* Walk through the list of descriptors and find a match */ static void ao_usb_get_descriptor(uint16_t value) { - const uint8_t *descriptor; + CONST uint8_t *descriptor; uint8_t type = value >> 8; uint8_t index = value; @@ -197,7 +196,7 @@ _ao_usb_ep0_setup(void) ao_usb_ep0_out_len = 8; _ao_usb_ep0_fill(8); - ao_usb_ep0_in_data = ao_usb_ep0_in_buf; + ao_usb_ep0_in_data = 0; ao_usb_ep0_in_len = 0; switch(ao_usb_setup.request) { case AO_USB_REQ_GET_STATUS: @@ -222,11 +221,11 @@ _ao_usb_ep0_setup(void) break; case AO_USB_SET_LINE_CODING: ao_usb_ep0_out_len = 7; - ao_usb_ep0_out_data = (uint8_t *) &ao_usb_line_coding; + ao_usb_ep0_out_data = (uint8_t *) &ao_usb_setup; break; case AO_USB_GET_LINE_CODING: ao_usb_ep0_in_len = 7; - ao_usb_ep0_in_data = (uint8_t *) &ao_usb_line_coding; + ao_usb_ep0_in_data = (CONST uint8_t *) &ao_usb_line_coding; break; case AO_USB_SET_CONTROL_LINE_STATE: break; diff --git a/chips/avr/dtoa.h b/chips/avr/dtoa.h new file mode 100644 index 00000000..d82e9d97 --- /dev/null +++ b/chips/avr/dtoa.h @@ -0,0 +1,58 @@ +/* Copyright © 2018, Keith Packard + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of the copyright holders nor the names of + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. */ + +#ifndef _DTOA_H_ +#define _DTOA_H_ + +#define DTOA_MINUS 1 +#define DTOA_ZERO 2 +#define DTOA_INF 4 +#define DTOA_NAN 8 + +#define DTOA_MAX_DIG 17 +#define DTOA_MAX_10_EXP 308 +#define DTOA_MIN_10_EXP (-307) +#define DTOA_SCALE_UP_NUM 9 +#define DTOA_ROUND_NUM (DTOA_MAX_DIG + 1) +#define DTOA_MAX_EXP 1024 + +#define FTOA_MAX_10_EXP 38 +#define FTOA_MIN_10_EXP (-37) +#define FTOA_MAX_DIG 9 +#define FTOA_SCALE_UP_NUM 6 +#define FTOA_ROUND_NUM (FTOA_MAX_DIG + 1) + +#define DTOA_DIGITS FTOA_MAX_DIG + +struct dtoa { + int32_t exp; + uint8_t flags; + char digits[DTOA_DIGITS]; +}; + +#endif /* !_DTOA_H_ */ diff --git a/chips/avr/ftoa_engine.c b/chips/avr/ftoa_engine.c new file mode 100644 index 00000000..42bc75af --- /dev/null +++ b/chips/avr/ftoa_engine.c @@ -0,0 +1,248 @@ +/* Copyright (c) 2005, Dmitry Xmelkov + All rights reserved. + Rewritten in C by Soren Kuula + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of the copyright holders nor the names of + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. */ + +#define _NEED_IO_FLOAT32 +#include +#include +#include +#include "dtoa.h" + +/* + * 2^b ~= f * r * 10^e + * where + * i = b div 8 + * r = 2^(b mod 8) + * f = factorTable[i] + * e = exponentTable[i] + */ +static const int8_t exponentTable[32] = { + -36, -33, -31, -29, -26, -24, -21, -19, + -17, -14, -12, -9, -7, -4, -2, 0, + 3, 5, 8, 10, 12, 15, 17, 20, + 22, 24, 27, 29, 32, 34, 36, 39 +}; + +static const uint32_t factorTable[32] = { + 2295887404UL, + 587747175UL, + 1504632769UL, + 3851859889UL, + 986076132UL, + 2524354897UL, + 646234854UL, + 1654361225UL, + 4235164736UL, + 1084202172UL, + 2775557562UL, + 710542736UL, + 1818989404UL, + 465661287UL, + 1192092896UL, + 3051757813UL, + 781250000UL, + 2000000000UL, + 512000000UL, + 1310720000UL, + 3355443200UL, + 858993459UL, + 2199023256UL, + 562949953UL, + 1441151881UL, + 3689348815UL, + 944473297UL, + 2417851639UL, + 618970020UL, + 1584563250UL, + 4056481921UL, + 1038459372UL +}; + +#define max(a, b) ({\ + __typeof(a) _a = a;\ + __typeof(b) _b = b;\ + _a > _b ? _a : _b; }) + +#define min(a, b) ({\ + __typeof(a) _a = a;\ + __typeof(b) _b = b;\ + _a < _b ? _a : _b; }) + +int __ftoa_engine(float val, char *buf, int maxDigits, int maxDecimals) +{ + uint8_t flags = 0; + struct dtoa dtoa, *ftoa = &dtoa; + union { + float v; + uint32_t u; + } x; + + x.v = val; + + uint32_t frac = x.u & 0x007fffffUL; + + maxDigits++; + if (maxDigits > FTOA_MAX_DIG) + maxDigits = FTOA_MAX_DIG; + + /* Read the sign, shift the exponent in place and delete it from frac. + */ + if (x.u & ((uint32_t)1 << 31)) + flags = DTOA_MINUS; + + uint8_t exp = x.u >> 23; + + ftoa->exp = 0; + + /* + * Test for easy cases, zero and NaN + */ + if(exp==0 && frac==0) + { + flags |= DTOA_ZERO; + memset(ftoa->digits, '0', maxDigits); + } else if(exp == 0xff) { + if(frac == 0) + flags |= DTOA_INF; + else + flags |= DTOA_NAN; + } else { + + /* The implicit leading 1 is made explicit, except if value + * subnormal, in which case exp needs to be adjusted by one + */ + if (exp == 0) + exp = 1; + else + frac |= (1UL<<23); + + uint8_t idx = exp>>3; + int8_t exp10 = exponentTable[idx]; + + /* + * We COULD try making the multiplication in situ, where we make + * frac and a 64 bit int overlap in memory and select/weigh the + * upper 32 bits that way. For starters, this is less risky: + */ + int64_t prod = (int64_t)frac * (int64_t)factorTable[idx]; + + /* + * The expConvFactorTable are factor are correct iff the lower 3 exponent + * bits are 1 (=7). Else we need to compensate by divding frac. + * If the lower 3 bits are 7 we are right. + * If the lower 3 bits are 6 we right-shift once + * .. + * If the lower 3 bits are 0 we right-shift 7x + */ + prod >>= (15-(exp & 7)); + + /* + * Now convert to decimal. + */ + + uint8_t hadNonzeroDigit = 0; /* have seen a non-zero digit flag */ + uint8_t outputIdx = 0; + int64_t decimal = 100000000000000ull; + uint8_t saveMaxDigits = maxDigits; + + do { + /* Compute next digit */ + char digit = prod / decimal + '0'; + + if(!hadNonzeroDigit) + { + /* Don't return results with a leading zero! Instead + * skip those and decrement exp10 accordingly. + */ + if (digit == '0') { + exp10--; + prod = prod % decimal; + decimal /= 10; + continue; + } + + /* Found the first non-zero digit */ + hadNonzeroDigit = 1; + } + prod = prod % decimal; + decimal /= 10; + + /* Now we have a digit. */ + if(digit < '0' + 10) { + /* normal case. */ + ftoa->digits[outputIdx] = digit; + } else { + /* + * Uh, oh. Something went wrong with our conversion. Write + * 9s and use the round-up code to report back to the caller + * that we've carried + */ + for(outputIdx = 0; outputIdx < maxDigits; outputIdx++) + ftoa->digits[outputIdx] = '9'; + goto round_up; + } + outputIdx++; + } while (outputIdx> 1) >= 0) + { + uint8_t rounded; + round_up: + + rounded = 0; + while(outputIdx != 0) { + + /* Increment digit, check if we're done */ + if(++ftoa->digits[outputIdx-1] < '0' + 10) { + rounded = 1; + break; + } + + ftoa->digits[--outputIdx] = '0'; + /* and the loop continues, carrying to next digit. */ + } + + if (!rounded) { + + /* Rounded past the first digit; + * reset the leading digit to 1, + * bump exp and tell the caller we've carried. + * The remaining digits will already be '0', + * so we don't need to mess with them + */ + ftoa->digits[0] = '1'; + exp10++; + } + } + ftoa->exp = exp10; + } + ftoa->flags = flags; + + buf[0] = flags; + memcpy(buf+1, ftoa->digits, maxDigits+1); + return ftoa->exp; +} diff --git a/chips/avr/snek-avr.defs b/chips/avr/snek-avr.defs index c5e86625..6ae7075a 100644 --- a/chips/avr/snek-avr.defs +++ b/chips/avr/snek-avr.defs @@ -16,18 +16,22 @@ SNEK_AO = $(SNEK_ROOT)/ao SNEK_PORT?=. -SNEK_LOCAL_VPATH = $(SNEK_PORT):$(SNEK_AVR):$(SNEK_AO) +SNEK_LOCAL_VPATH = $(SNEK_AVR):$(SNEK_AO) + +vpath ao-pins.h $(SNEK_PORT) SNEK_AVR_SRC = \ snek-io.c \ snek-pow.c \ snek-random-small.c \ + snek-input.c \ snek-avr-eeprom.c \ ao-snek-avr.c \ ao-usb-avr.c \ ao-notask.c \ ao-product.c \ - snek-atof.c + snek-atof.c \ + strfromg.c SNEK_AVR_INC = \ ao.h \ @@ -45,27 +49,44 @@ SNEK_AVR_BUILTINS = \ snek-gpio.builtin \ snek-eeprom.builtin \ snek-random.builtin \ + snek-input.builtin \ snek-avr.builtin SNEK_NO_FILE = 1 -OPT=-Os -frename-registers -funsigned-char -fno-jump-tables -mcall-prologues +#OPT=-Os -frename-registers -funsigned-char -fno-jump-tables -mcall-prologues + +OPT=-Os \ + -mrelax \ + -Wno-array-bounds \ + -frename-registers \ + -funsigned-char \ + -mcall-prologues \ + -fno-move-loop-invariants \ + -fno-move-loop-stores \ + -fno-split-loops \ + -fno-unswitch-loops \ + -fno-unroll-loops \ + -fno-peel-loops SNEK_CFLAGS = $(SNEK_MOST_WARNINGS) $(SNEK_BASE_CFLAGS) AO_CFLAGS=\ - -std=c99 $(OPT) -g + $(OPT) -g AVR_CFLAGS=-DF_CPU=$(AVR_CLOCK) -mmcu=atmega32u4 -g $(SNEK_CFLAGS) -Waddr-space-convert \ -I. -I$(SNEK_PORT) -I$(SNEK_AVR) -I$(SNEK_AO) -I$(SNEK_ROOT) $(AO_CFLAGS) -CFLAGS = $(AVR_CFLAGS) $(SNEK_CFLAGS) +AVR_FLASH_SIZE ?= 0x7e00 + +CFLAGS = $(SNEK_CFLAGS) $(AVR_CFLAGS) LDSCRIPT=$(SNEK_AVR)/snek-avr51.x LDFLAGS=$(SNEK_LDFLAGS) \ - -Wl,-uvfprintf -lprintf_flt -lm \ + -lm \ -Wl,-T$(LDSCRIPT) \ + -Wl,--defsym -Wl,__TEXT_REGION_LENGTH__=$(AVR_FLASH_SIZE) \ -Wl,-Map=$(MAP) CC=avr-gcc diff --git a/chips/avr/snek-avr.h b/chips/avr/snek-avr.h index 94585757..aebeac7c 100644 --- a/chips/avr/snek-avr.h +++ b/chips/avr/snek-avr.h @@ -36,76 +36,66 @@ float atoff(const char *); #define VALUE_STACK_SIZE 16 #define PARSE_STACK_SIZE 128 #define SNEK_STACK 32 -#define PARSE_TABLE_DECLARATION(t) PROGMEM t -#define PARSE_TABLE_FETCH_TOKEN(a) ((token_key_t) pgm_read_byte(a)) -#define PARSE_TABLE_FETCH_INDEX(a) ((uint8_t) pgm_read_byte(a)) -#define ERROR_FETCH_FORMAT_CHAR(a) ((char) pgm_read_byte(a)) + +#ifndef CONST +#define CONST const __flash +#endif /* no sense linking both functions */ #define memcpy(a,b,c) memmove(a,b,c) #define snek_error_name snek_internal_error #define snek_error(fmt, args...) ({ \ - static const char PROGMEM __fmt__[] = (fmt); \ + static CONST char __fmt__[] = (fmt); \ snek_internal_error(__fmt__, ## args); \ }) #define snek_error_0_name snek_internal_error_0 #define snek_error_0(string) ({ \ - static const char PROGMEM __string__[] = (string); \ + static CONST char __string__[] = (string); \ snek_internal_error_0(__string__); \ }) #define fprintf(file, fmt, args...) ({ \ - static const char PROGMEM __fmt__[] = (fmt); \ - printf_P(__fmt__, ## args); \ + static CONST char __fmt__[] = (fmt); \ + printf_P((const char *) (uintptr_t) __fmt__, ## args); \ }) #define sprintf_const(dst, fmt, args...) ({ \ - static const char PROGMEM __fmt__[] = (fmt); \ - sprintf_P(dst, __fmt__, ##args); \ + static CONST char __fmt__[] = (fmt); \ + sprintf_P(dst, (const char *) (uintptr_t) __fmt__, ##args); \ + }) + +int +strfromg(char *dst0, float val); + +//#define strfromf_const(dst, len, fmt, val) sprintf_const(dst, fmt, val) +//#define strfromf(dst, len, fmt, val) sprintf(dst, fmt, val) +#define strfromf(dst, len, fmt, val) strfromg(dst, val) + +#define trailing(next, wo_op, wo, w_op, w) ({ \ + static CONST char __next__[] = (next); \ + trailing_internal(__next__, wo_op, wo, w_op, w); \ + }) +#define trailing_name trailing_internal + +#define snek_const_strcmp(a,b) strcmp_P(a,(const char *) (uintptr_t) (b)) + +#define snek_const_strcpy(a,b) ({ \ + static CONST char __str__[] = (b); \ + strcpy_P(a, (const char *) (uintptr_t) (__str__)); \ }) -#define strfromf_const(dst, len, fmt, val) sprintf_const(dst, fmt, val) -#define strfromf(dst, len, fmt, val) sprintf(dst, fmt, val) - -#define SNEK_BUILTIN_NAMES_DECLARE(n) PROGMEM n -#define SNEK_BUILTIN_NAMES(a) ((uint8_t) pgm_read_byte(&snek_builtin_names[a])) -#define SNEK_BUILTIN_NAMES_CMP(a,b) strcmp_P(a,b) - -#define SNEK_BUILTIN_DECLARE(n) PROGMEM n -#define SNEK_BUILTIN_NFORMAL(b) ((int8_t) pgm_read_byte(&(b)->nformal)) -#define SNEK_BUILTIN_FUNCV(b) ((snek_poly_t(*)(uint8_t, uint8_t, snek_poly_t *)) pgm_read_ptr(&(b)->funcv)) -#define SNEK_BUILTIN_FUNC0(b) ((snek_poly_t(*)(void)) pgm_read_ptr(&(b)->func0)) -#define SNEK_BUILTIN_FUNC1(b) ((snek_poly_t(*)(snek_poly_t)) pgm_read_ptr(&(b)->func1)) -#define SNEK_BUILTIN_FUNC2(b) ((snek_poly_t(*)(snek_poly_t, snek_poly_t)) pgm_read_ptr(&(b)->func2)) -#define SNEK_BUILTIN_FUNC3(b) ((snek_poly_t(*)(snek_poly_t, snek_poly_t, snek_poly_t)) pgm_read_ptr(&(b)->func3)) -#define SNEK_BUILTIN_FUNC4(b) ((snek_poly_t(*)(snek_poly_t, snek_poly_t, snek_poly_t, snek_poly_t)) pgm_read_ptr(&(b)->func4)) -#define SNEK_BUILTIN_VALUE(b) ((snek_poly_t)(uint32_t)pgm_read_dword(&(b)->value)) - -#define SNEK_ROOT_DECLARE(n) PROGMEM n -#define SNEK_ROOT_TYPE(n) ((const snek_mem_t *) pgm_read_ptr(&(n)->type)) -#define SNEK_ROOT_ADDR(n) ((void **) pgm_read_ptr(&(n)->addr)) static inline const char * -avr_snek_builtin_names_return(const uint8_t *bits) +avr_snek_builtin_names_return(CONST uint8_t *bits) { static char ret[SNEK_BUILTIN_NAMES_MAX_LEN + 1]; - char *r = ret; - while ((*r++ = (char) pgm_read_byte(bits++))) - ; - return ret; + return strcpy_P(ret, (const char *) (uintptr_t) bits); } #define snek_builtin_names_return(a) avr_snek_builtin_names_return(a) -#define snek_builtin_names_len(a) strnlen_P(a, SNEK_BUILTIN_NAMES_MAX_LEN+1) - -#define SNEK_MEM_DECLARE(n) PROGMEM n -#define SNEK_MEM_SIZE(m) ((snek_offset_t (*)(void *addr)) pgm_read_word(&(m)->size)) -#define SNEK_MEM_MARK(m) ((void (*)(void *addr)) pgm_read_ptr(&(m)->mark)) -#define SNEK_MEM_MOVE(m) ((void (*)(void *addr)) pgm_read_ptr(&(m)->move)) - -#define SNEK_MEMS_DECLARE(n) PROGMEM n +#define snek_builtin_names_len(a) strnlen_P((const char *) (uintptr_t) a, SNEK_BUILTIN_NAMES_MAX_LEN+1) int snek_eeprom_getchar(FILE *stream); diff --git a/chips/avr/strfromg-test.c b/chips/avr/strfromg-test.c new file mode 100644 index 00000000..0705fe9a --- /dev/null +++ b/chips/avr/strfromg-test.c @@ -0,0 +1,70 @@ +/* + * Copyright © 2024 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#define __STDC_WANT_IEC_60559_BFP_EXT__ +#include +#include +#include +#include +#include "strfromg.h" + +static float +int_exp10(int n) +{ + float a = 1.0f; + int sign = n < 0; + + if (sign) + n = -n; + while (n--) + a *= 10.0f; + if (sign) + a = 1/a; + return a; +} + +static const float test_vals[] = { 1.234567f, 1.1f, (float) M_PI }; + +int +main(int argc, char **argv) +{ + char buf[16]; + char libc[16]; + int x; + int i; + int ret = 0; + + for (i = 1; i < argc; i++) { + float val = strtof(argv[i], NULL); + strfromg(buf, val); + strfromf(libc, sizeof(libc), "%.8g", val); + printf("libc '%s' snek '%s'\n", libc, buf); + } + for (x = -45; x <= 38; x++) + { + float r; + unsigned t; + for (t = 0; t < sizeof(test_vals)/sizeof(test_vals[0]); t++) { + float v = test_vals[t] * int_exp10(x); + float e; + strfromg(buf, v); + strfromf(libc, sizeof(libc), "%.8g", v); + if (strcmp(buf, libc)) { + printf("libc %s snek %s\n", libc, buf); + ret = 1; + } + } + } + return ret; +} diff --git a/chips/avr/strfromg.c b/chips/avr/strfromg.c new file mode 100644 index 00000000..8dd7ec64 --- /dev/null +++ b/chips/avr/strfromg.c @@ -0,0 +1,112 @@ +/* + * Copyright © 2024 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef STRFROMG_TEST +#include "snek.h" +#else +#include +#define snek_const_strcpy(a,b) strcpy(a,b) +#endif + +#include "strfromg.h" +#include + +int __ftoa_engine (float val, char *buf, + unsigned char prec, unsigned char maxdgs); + +/* '__ftoa_engine' return next flags (in buf[0]): */ +#define FTOA_MINUS 1 +#define FTOA_ZERO 2 +#define FTOA_INF 4 +#define FTOA_NAN 8 +#define FTOA_CARRY 16 /* Carry was to master position. */ + +#define PREC 7 + +int +strfromg(char *dst0, float val) +{ + char *dst = dst0; + char buf[1 + 1 + PREC + 1]; + int exp; + uint8_t vtype; + uint8_t prec = PREC; + uint8_t fix = 0; + int ndigs = 0; + int n; + char c; + + exp = __ftoa_engine(val, buf, prec, 0); + vtype = buf[0]; + if (vtype & FTOA_MINUS) + *dst++ = '-'; + if (vtype & FTOA_NAN) { + snek_const_strcpy(dst, "nan"); + dst += 3; + } else if (vtype & FTOA_INF) { + snek_const_strcpy(dst, "inf"); + dst += 3; + } else { + if (-4 <= exp && exp <= prec) + fix = 1; + while (prec && buf[1+prec] == '0') + prec--; + if (fix) { /* 'f' format */ + ndigs = prec + 1; + if (prec > exp) + prec = prec - exp; + else + prec = 0; + n = exp > 0 ? exp : 0; + for (;;) { + if (n == -1) + *dst++ = '.'; + c = (n <= exp && n > exp - ndigs) ? buf[exp - n + 1] : '0'; + if (--n < -prec) + break; + *dst++ = c; + } + if (n == exp && + (buf[1] > '5' + || (buf[1] == '5' && !(vtype & FTOA_CARRY)))) + c = '1'; + *dst++ = c; + } else { /* 'g' format */ + if (buf[1] != '1') + vtype &= ~FTOA_CARRY; + *dst++ = buf[1]; + if (prec) { + uint8_t dig = 2; + *dst++ = '.'; + do { + *dst++ = buf[dig++]; + } while (--prec); + } + + /* exponent */ + *dst++ = 'e'; + c = '+'; + if (exp < 0 || (exp == 0 && (vtype & FTOA_CARRY))) { + exp = -exp; + c = '-'; + } + *dst++ = c; + *dst++ = (exp / 10) + '0'; + *dst++ = (exp % 10) + '0'; + } + + *dst = '\0'; + } + return dst - dst0; +} diff --git a/chips/avr/strfromg.h b/chips/avr/strfromg.h new file mode 100644 index 00000000..b6779142 --- /dev/null +++ b/chips/avr/strfromg.h @@ -0,0 +1,2 @@ +int +strfromg(char *dst0, float val); diff --git a/chips/qemu/snek-qemu.h b/chips/qemu/snek-qemu.h index a612fd86..723e1c5a 100644 --- a/chips/qemu/snek-qemu.h +++ b/chips/qemu/snek-qemu.h @@ -27,6 +27,8 @@ extern int snek_qemu_getc(void); #define abort() exit(1) +#define CONST const + #if _PICOLIBC__ == 1 && (_PICOLIBC_MINOR__ < 6 || __PICOLIBC_PATCHLEVEL__ < 1) #define _SNEK_NEED_STRFROMF int diff --git a/chips/samd21/ao-arch.h b/chips/samd21/ao-arch.h index 838d8983..88404d24 100644 --- a/chips/samd21/ao-arch.h +++ b/chips/samd21/ao-arch.h @@ -22,6 +22,8 @@ #include #include +#define CONST const + /* * Samd21 definitions and code fragments for AltOS */ diff --git a/chips/samd21/snek-gpio.c b/chips/samd21/snek-gpio.c index 9a96e42a..85080961 100644 --- a/chips/samd21/snek-gpio.c +++ b/chips/samd21/snek-gpio.c @@ -737,7 +737,10 @@ snek_builtin_neopixel(snek_poly_t pixels) list_size = 1; if (snek_neopixels == NULL || snek_neopixel_count < list_size) { + snek_stack_push_list(pixels_list); snek_neopixels = snek_alloc(list_size * sizeof (struct snek_neopixel)); + pixels_list = snek_stack_pop_list(); + pixels_data = snek_list_data(pixels_list); if (!snek_neopixels) return SNEK_NULL; snek_neopixel_count = list_size; @@ -746,7 +749,7 @@ snek_builtin_neopixel(snek_poly_t pixels) if (is_immediate) set_neopixel(0, pixels); else { - for (int p = 0; p < pixels_list->size; p++) { + for (int p = 0; p < list_size; p++) { set_neopixel(p, pixels_data[p]); if (snek_abort) return SNEK_NULL; diff --git a/chips/samd21/uf2conv.py b/chips/samd21/uf2conv.py index d4f179ec..2aeb5417 100755 --- a/chips/samd21/uf2conv.py +++ b/chips/samd21/uf2conv.py @@ -223,7 +223,7 @@ def get_drives(): ] ) for line in r.split("\n"): - words = re.split("\s+", line) + words = re.split("\\s+", line) if len(words) >= 3 and words[1] == "2" and words[2] == "FAT": drives.append(words[0]) else: diff --git a/examples/morse.py b/examples/morse.py index 8aa9f6a2..f1584e30 100644 --- a/examples/morse.py +++ b/examples/morse.py @@ -72,9 +72,9 @@ def m(t): def cq(): - talkto(D13) + talkto(LED) while True: - m("cq cq de kd7sqg ") + m("cq cq de k7wq ") cq() diff --git a/hosts/linux/Makefile b/hosts/linux/Makefile index c1850eae..a8e1f91a 100644 --- a/hosts/linux/Makefile +++ b/hosts/linux/Makefile @@ -26,7 +26,7 @@ PROGS= \ $(SNEK_PORTS)/posix/snek \ $(SNEK_ROOT)/snekde/snekde \ $(SNEK_PORTS)/duemilanove/snek-duemilanove-install.in \ - $(SNEK_PORTS)/itsybitsy5v/snek-itsybitsy-install.in \ + $(SNEK_PORTS)/itsybitsy5v/snek-atmega32u4-install.in \ $(SNEK_PORTS)/mega/snek-mega-install.in \ $(SNEK_PORTS)/uno/snek-uno-install.in @@ -39,7 +39,7 @@ DOC= \ $(SNEK_ROOT)/snekde/snekde.1 \ $(SNEK_ROOT)/COPYING \ $(SNEK_PORTS)/duemilanove/snek-duemilanove-install.1 \ - $(SNEK_PORTS)/itsybitsy5v/snek-itsybitsy-install.1 \ + $(SNEK_PORTS)/itsybitsy5v/snek-atmega32u4-install.1 \ $(SNEK_PORTS)/mega/snek-mega-install.1 \ $(SNEK_PORTS)/uno/snek-uno-install.1 diff --git a/hosts/windows/snek-windows.h b/hosts/windows/snek-windows.h index ce3c1520..322ae0bf 100644 --- a/hosts/windows/snek-windows.h +++ b/hosts/windows/snek-windows.h @@ -25,4 +25,6 @@ int snek_getc(FILE *input); #define isnanf(x) __isnanf(x) +#define CONST const + #endif /* _SNEK_WINDOWS_H_ */ diff --git a/ports/duemilanove-big/.gitignore b/ports/duemilanove-big/.gitignore deleted file mode 100644 index 1141d27d..00000000 --- a/ports/duemilanove-big/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -snek-duemilanove-big-*.elf -snek-duemilanove-big-*.map -snek-duemilanove-big-*.hex -snek-duemilanove-big-install -snek-duemilanove-big-install.1 diff --git a/ports/duemilanove-big/Makefile b/ports/duemilanove-big/Makefile deleted file mode 100644 index ec1ca79d..00000000 --- a/ports/duemilanove-big/Makefile +++ /dev/null @@ -1,62 +0,0 @@ -# -# Copyright © 2020 Keith Packard -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# - -vpath %.in ../duemilanove-big - -BOARD?=duemilanove-big -CBOARD?=Duemilanove-big -UBOARD?=DUEMILANOVE-BIG -PORT?=/dev/ttyUSB0 -INSTALLER?=0 - -ATMEGA_FLASH_SIZE=0x8000 - -SNEK_ATMEGA_SRC_EXTRA ?= \ - snek-input.c - -SNEK_ATMEGA_BUILTINS_EXTRA ?= \ - snek-input.builtin - -include ../duemilanove/Makefile - -all:: snek-$(BOARD)-install snek-$(BOARD)-install.1 - -snek-$(BOARD)-install: snek-duemilanove-big-install.in - $(SNEK_ATMEGA_SED) $^ > $@ - chmod +x $@ - -install:: $(HEX) - install -d $(DESTDIR)$(SHAREDIR) - install -m 0644 $(HEX) $(DESTDIR)$(SHAREDIR) - -install:: snek-$(BOARD)-install snek-$(BOARD)-install.1 - install -d $(DESTDIR)$(BINDIR) - install snek-$(BOARD)-install $(DESTDIR)$(BINDIR) - install -d $(DESTDIR)$(MANDIR)/man1 - install -m 0644 snek-$(BOARD)-install.1 $(DESTDIR)$(MANDIR)/man1 - -clean:: - rm -f snek-$(BOARD)-install snek-$(BOARD)-install.1 - rm -f *.hex *.elf *.map - rm -f ao-product.h - -uninstall:: - -ISP=avrisp2 - -load: $(HEX) snek-$(BOARD)-install - ./snek-$(BOARD)-install -quick -isp $(ISP) -hex $(HEX) load - -snek-$(BOARD)-install.1: snek-duemilanove-big-install.1.in - $(SNEK_ATMEGA_SED) $^ > $@ diff --git a/ports/duemilanove-big/snek-duemilanove-big-install.1.in b/ports/duemilanove-big/snek-duemilanove-big-install.1.in deleted file mode 100644 index 86e27da4..00000000 --- a/ports/duemilanove-big/snek-duemilanove-big-install.1.in +++ /dev/null @@ -1,59 +0,0 @@ -.\" -.\" Copyright © 2021 Keith Packard -.\" -.\" This program is free software; you can redistribute it and/or modify -.\" it under the terms of the GNU General Public License as published by -.\" the Free Software Foundation, either version 3 of the License, or -.\" (at your option) any later version. -.\" -.\" This program is distributed in the hope that it will be useful, but -.\" WITHOUT ANY WARRANTY; without even the implied warranty of -.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -.\" General Public License for more details. -.\" -.TH SNEK-@UBOARD@-INSTALL 1 "snek-@BOARD@-install" "" -.SH NAME -snek-@BOARD@-big-install \- Install larger version of Snek to -Arduino ATmega328 board -.SH SYNOPSIS -.B "snek-@BOARD@-install" [OPTION]... [COMMAND] -.SH DESCRIPTION -.I snek-@BOARD@-install -installs the larger version Snek programming language on an Arduino -board with an ATmega328, overwriting the boot loader. This -version of snek provides support for a few extra -functions, 'input', 'float' and 'int'. As a consequence, it does not -leave room for the Optiboot loader and must be flashed using a -separate programmer dongle. -.SH OPTIONS -.TP -\-isp -Specifies the programmer to use, common options are 'usbtiny' -and 'avrisp2'. The default is 'usbtiny'. -.TP -\-hex -Specifies the hex file to load to the board. The default is the -currently installed version of Snek. -.TP -\-mcu -Specifies which micro controller to expect to find on the board. Some -boards have m328 while others have m328p. The default is @MCU@, but if -you get an error message indicating a mismatch, you can try the other. -.SH COMMANDS -.TP -fuseload -Sets the target fuse bits for Snek usage and then loads Snek to the -device. This is the default command -.TP -load -Loads Snek to the device without first setting the fuse bits. Snek -will not work correctly if the fuse bits are not set correctly, so -only do this if the target has already had the fuse bits set correctly. -.TP -fuse -Sets the target fuse bits suitable for Snek usage. You must do this -before Snek will work on the target device, although you may do it -before or after loading the Snek system. You only need to do this once -per board. -.SH AUTHOR -Keith Packard diff --git a/ports/duemilanove-big/snek-duemilanove-big-install.in b/ports/duemilanove-big/snek-duemilanove-big-install.in deleted file mode 100644 index 10134ca9..00000000 --- a/ports/duemilanove-big/snek-duemilanove-big-install.in +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/sh - -SHAREDIR="@SHAREDIR@" - -SNEKBIGBASE="$SHAREDIR/snek-@BOARD@" -SNEKBIGREST="-@SNEK_VERSION@.hex" -SNEKBIG="$SNEKBIGBASE""$SNEKBIGREST" - -action="fuseload" - -ISP=usbtiny - -mode=arg - -verify="" - -MCU="@MCU@" - -for i in "$@"; do - case "$mode" in - arg) - case "$i" in - fuse|load|fuseload) - action="$i" - ;; - -isp|--isp) - mode=isp - ;; - -hex|--hex) - mode=hex - ;; - -mcu|--mcu) - mode=mcu - ;; - -quick) - verify="-V" - ;; - *) - echo "Usage: $0 {-isp usbtiny} {-isp avrisp2} {-hex snek-uduino.hex} {-mcu 328} {fuseload|load|fuse}" 1>&2 - exit 1 - ;; - esac - ;; - isp) - ISP="$i" - mode=arg - ;; - hex) - SNEKBIG="$i" - mode=arg - ;; - mcu) - MCU="$i" - mode=arg; - ;; - esac -done - -FUSES="-U hfuse:w:0xd1:m" - -case "$action" in - fuse|fuseload) - avrdude -V -c $ISP -p $MCU -u $FUSES || exit 1 - ;; -esac - -case "$action" in - fuseload|load) - avrdude $verify -c $ISP -p $MCU -U flash:w:"${SNEKBIG}" || exit 1 - ;; -esac diff --git a/ports/duemilanove/.gitignore b/ports/duemilanove/.gitignore index 60484a8f..296b5512 100644 --- a/ports/duemilanove/.gitignore +++ b/ports/duemilanove/.gitignore @@ -2,4 +2,5 @@ snek-duemilanove-*.elf snek-duemilanove-*.hex snek-duemilanove-*.map snek-duemilanove-install +snek-duemilanove-install.in snek-duemilanove-install.1 diff --git a/ports/duemilanove/Makefile b/ports/duemilanove/Makefile index 0a6751d8..0dde1c5f 100644 --- a/ports/duemilanove/Makefile +++ b/ports/duemilanove/Makefile @@ -24,7 +24,7 @@ CLOCK?=16000000 BAUD?=115200 INSTALLER?=1 ATMEGA_FLASH_SIZE?=0x7e00 -MCU?=m328 +MCU?=m328p include $(SNEK_ATMEGA)/snek-atmega.defs @@ -42,6 +42,7 @@ SNEK_LOCAL_INC = \ SNEK_LOCAL_BUILTINS = \ $(SNEK_ATMEGA_BUILTINS) \ $(SNEK_ATMEGA_BUILTINS_EXTRA) \ + snek-tone.builtin \ snek-328p.builtin include $(SNEK_ROOT)/snek-install.defs @@ -54,6 +55,19 @@ SNEK_ATMEGA_SED=$(SNEK_SED) \ -e 's;@PORT@;$(PORT);g' \ -e 's;@MCU@;$(MCU);g' +SNEK_ATMEGA_BOARD_SED = sed \ + -e 's;@SNEKLIB@;$(SNEKLIB);' \ + -e 's/@SNEK_VERSION@/$(SNEK_VERSION)/' \ + -e 's/@SNEK_VERSION_DASH@/$(SNEK_VERSION_DASH)/' \ + -e 's;@SNEK_ROOT@;$(SNEK_ROOT);' \ + -e 's/@SNEK_DATE@/$(SNEK_DATE)/' \ + -e 's;@BOARD@;$(BOARD);g' \ + -e 's;@UBOARD@;$(UBOARD);g' \ + -e 's;@CBOARD@;$(CBOARD);g' \ + -e 's;@BAUD@;$(BAUD);g' \ + -e 's;@PORT@;$(PORT);g' \ + -e 's;@MCU@;$(MCU);g' + SNEK_CFLAGS = $(SNEK_MOST_WARNINGS) $(SNEK_BASE_CFLAGS) BASE=snek-$(BOARD)-$(SNEK_VERSION) @@ -62,11 +76,9 @@ HEX=$(BASE).hex MAP=$(BASE).map CC=avr-gcc -OPT=-Os -frename-registers -funsigned-char -fno-jump-tables -mcall-prologues - -CFLAGS=$(OPT) -DUART_BAUD=$(BAUD) -DF_CPU=$(CLOCK)UL -mmcu=atmega328p -I. -I$(SNEK_LOCAL_VPATH) -g $(SNEK_CFLAGS) -Waddr-space-convert +CFLAGS=-DUART_BAUD=$(BAUD) -DF_CPU=$(CLOCK)UL -mmcu=atmega328p -I. -I$(SNEK_LOCAL_VPATH) $(SNEK_CFLAGS) $(OPT) -g -Waddr-space-convert LDFLAGS=$(SNEK_LDFLAGS) \ - -Wl,-uvfprintf -lprintf_flt -lm \ + -lm \ -Wl,--defsym -Wl,__TEXT_REGION_LENGTH__=$(ATMEGA_FLASH_SIZE) \ -Wl,-Map=$(MAP) @@ -77,15 +89,18 @@ $(HEX): $(ELF) $(ELF): $(SNEK_OBJ) $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) - @gawk '/__data_load_end/{printf("ROM used: %d bytes\n", strtonum($$1)); }' $(MAP) + @gawk '/__data_load_end/{printf("$(BASE) ROM: %d bytes\n", strtonum($$1)); }' $(MAP) ifeq ($(INSTALLER),1) -all:: snek-$(BOARD)-install snek-$(BOARD)-install.1 +all:: snek-$(BOARD)-install snek-$(BOARD)-install.in snek-$(BOARD)-install.1 -snek-$(BOARD)-install: snek-duemilanove-install.in +snek-$(BOARD)-install: snek-atmega328-install.in $(SNEK_ATMEGA_SED) $^ > $@ chmod +x $@ +snek-$(BOARD)-install.in: snek-atmega328-install.in + if [ $@ != $^ ]; then $(SNEK_ATMEGA_BOARD_SED) $^ > $@; fi + load: $(HEX) snek-$(BOARD)-install ./snek-$(BOARD)-install -hex $(HEX) @@ -103,4 +118,4 @@ install: snek-$(BOARD)-install $(HEX) snek-$(BOARD)-install.1 endif clean:: - rm -f *.elf *.hex *.map snek-$(BOARD)-install snek-$(BOARD)-install.1 + rm -f *.elf *.hex *.map snek-$(BOARD)-install snek-$(BOARD)-install.in snek-$(BOARD)-install.1 diff --git a/ports/duemilanove/snek-duemilanove-install.in b/ports/duemilanove/snek-atmega328-install.in similarity index 100% rename from ports/duemilanove/snek-duemilanove-install.in rename to ports/duemilanove/snek-atmega328-install.in diff --git a/ports/ev3/snek-ev3.h b/ports/ev3/snek-ev3.h index cc961ca2..7cb740a3 100644 --- a/ports/ev3/snek-ev3.h +++ b/ports/ev3/snek-ev3.h @@ -44,4 +44,6 @@ snek_getc(void); #define SNEK_GETC() snek_getc() #define SNEK_IO_GETC(file) getc(file) +#define CONST const + #endif /* _SNEK_EV3_H_ */ diff --git a/ports/grove/Makefile b/ports/grove/Makefile index 608eae10..bfd5a32a 100644 --- a/ports/grove/Makefile +++ b/ports/grove/Makefile @@ -15,7 +15,7 @@ SNEK_ROOT = ../.. SNEK_ATMEGA = $(SNEK_ROOT)/chips/atmega SNEK_NO_DICT = 1 -SNEK_NO_SLICE = 1 +#SNEK_NO_SLICE = 1 include $(SNEK_ATMEGA)/snek-atmega.defs @@ -27,7 +27,6 @@ SNEK_LOCAL_SRC = \ snek-atmega-i2c.c \ snek-ssd1315.c \ snek-lis3dh.c \ - snek-input.c \ $(SNEK_ATMEGA_SRC) SNEK_LOCAL_INC = \ @@ -49,11 +48,9 @@ HEX=$(BASE).hex MAP=$(BASE).map CC=avr-gcc -OPT=-Os -frename-registers -funsigned-char -fno-jump-tables -mcall-prologues - -CFLAGS=$(OPT) -DF_CPU=16000000UL -mmcu=atmega328p -I. -I$(SNEK_LOCAL_VPATH) -g $(SNEK_CFLAGS) -Waddr-space-convert +CFLAGS=-DF_CPU=16000000UL -mmcu=atmega328p -I. -I$(SNEK_LOCAL_VPATH) -g $(SNEK_CFLAGS) $(OPT) -Waddr-space-convert LDFLAGS=$(SNEK_LDFLAGS) \ - -Wl,-uvfprintf -lprintf_flt -lm \ + -lm \ -Wl,--defsym -Wl,__TEXT_REGION_LENGTH__=0x7e00 \ -Wl,-Map=$(MAP) @@ -64,7 +61,7 @@ $(HEX): $(ELF) $(ELF): $(SNEK_OBJ) $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) - @gawk '/__data_load_end/{printf("ROM used: %d bytes\n", strtonum($$1)); }' $(MAP) + @gawk '/__data_load_end/{printf("$(BASE) ROM: %d bytes\n", strtonum($$1)); }' $(MAP) snek-grove-install: snek-grove-install.in $(SNEK_SED) $^ > $@ diff --git a/ports/grove/snek-grove.builtin b/ports/grove/snek-grove.builtin index b81d8a2e..cee48d6a 100644 --- a/ports/grove/snek-grove.builtin +++ b/ports/grove/snek-grove.builtin @@ -13,10 +13,7 @@ # A6, -2, 20 accel, 0 -float, 1 -int, 1 tone, 1 tonefor, 2 -#define SNEK_POOL 800 -#define PARSE_STACK_SIZE 64 -#define SNEK_STACK 16 +#define SNEK_POOL 700 +#define SNEK_STACK 32 diff --git a/ports/itsybitsy5v/.gitignore b/ports/itsybitsy5v/.gitignore index ac91605d..af95874b 100644 --- a/ports/itsybitsy5v/.gitignore +++ b/ports/itsybitsy5v/.gitignore @@ -1,5 +1,5 @@ snek-itsybitsy5v-*.elf snek-itsybitsy5v-*.hex snek-itsybitsy5v-*.map -snek-itsybitsy-install +snek-atmega32u4-install ao-product.h diff --git a/ports/itsybitsy5v/Makefile b/ports/itsybitsy5v/Makefile index c0f65d2d..e323b164 100644 --- a/ports/itsybitsy5v/Makefile +++ b/ports/itsybitsy5v/Makefile @@ -17,6 +17,7 @@ SNEK_AVR = $(SNEK_ROOT)/chips/avr BUILD_INSTALL?=1 PROGNAME?=snek-itsybitsy5v +UBANAME=$(shell echo $(PROGNAME) | sed 's/snek/ubaboot/') PRODUCT_NAME?=SnekItsyBitsy5v AVR_CLOCK?=16000000UL @@ -36,7 +37,7 @@ SNEK_LOCAL_BUILTINS = \ include $(SNEK_ROOT)/snek-install.defs ifeq ($(BUILD_INSTALL),1) -INSTALLER=snek-itsybitsy-install +INSTALLER=snek-atmega32u4-install else INSTALLER= endif @@ -45,22 +46,22 @@ all: $(ELF) $(HEX) $(INSTALLER) $(PROG): Makefile $(SNEK_OBJ) $(CC) $(CFLAGS) -o $@ $(SNEK_OBJ) $(LDFLAGS) - @gawk '/__data_load_end/{printf("ROM used: %d bytes\n", strtonum($$1)); }' $(MAP) + @gawk '/__data_load_end/{printf("$(BASE) ROM: %d bytes\n", strtonum($$1)); }' $(MAP) install:: $(HEX) install -d $(DESTDIR)$(SHAREDIR) install -m 0644 $(HEX) $(DESTDIR)$(SHAREDIR) ifeq ($(BUILD_INSTALL),1) -snek-itsybitsy-install: ../itsybitsy5v/snek-itsybitsy-install.in +snek-atmega32u4-install: ../itsybitsy5v/snek-atmega32u4-install.in $(SNEK_SED) $^ > $@ chmod +x $@ -install:: snek-itsybitsy-install snek-itsybitsy-install.1 +install:: snek-atmega32u4-install snek-atmega32u4-install.1 install -d $(DESTDIR)$(BINDIR) - install snek-itsybitsy-install $(DESTDIR)$(BINDIR) + install snek-atmega32u4-install $(DESTDIR)$(BINDIR) install -d $(DESTDIR)$(MANDIR)/man1 - install -m 0644 snek-itsybitsy-install.1 $(DESTDIR)$(MANDIR)/man1 + install -m 0644 snek-atmega32u4-install.1 $(DESTDIR)$(MANDIR)/man1 endif clean:: @@ -69,7 +70,13 @@ clean:: uninstall:: -ISP=avrisp2 +ISP=usbtiny -load: all - ../itsybitsy5v/snek-itsybitsy-install -quick -isp $(ISP) -hex $(HEX) load +UBAHEX=../../ubaboot/$(UBANAME).hex +UBABOOT=../../ubaboot/ubaboot.py + +load: all $(UBABOOT) + ../itsybitsy5v/snek-atmega32u4-install -hex $(HEX) -ubaboot $(UBABOOT) load + +fuseboot: $(UBAHEX) $(UBABOOT) + ../itsybitsy5v/snek-atmega32u4-install -isp $(ISP) -ubahex $(UBAHEX) fuseboot diff --git a/ports/itsybitsy5v/snek-atmega32u4-install.1 b/ports/itsybitsy5v/snek-atmega32u4-install.1 new file mode 100644 index 00000000..260b0dbe --- /dev/null +++ b/ports/itsybitsy5v/snek-atmega32u4-install.1 @@ -0,0 +1,63 @@ +.\" +.\" Copyright © 2019 Keith Packard +.\" +.\" This program is free software; you can redistribute it and/or modify +.\" it under the terms of the GNU General Public License as published by +.\" the Free Software Foundation, either version 3 of the License, or +.\" (at your option) any later version. +.\" +.\" This program is distributed in the hope that it will be useful, but +.\" WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +.\" General Public License for more details. +.\" +.TH SNEK-atmega32u4-INSTALL 1 "snek-atmega32u4-install" "" +.SH NAME +snek-atmega32u4-install \- Install Snek to ATmega32u4 +.SH SYNOPSIS +.B "snek-atmega32u4-install" [OPTION]... [COMMAND] +.SH DESCRIPTION +.I snek-atmega32u4-install +installs the Snek programming language on a device +with an ATmega32u4. +.SH OPTIONS +.TP +\-isp +Specifies the programmer to use, common options are 'usbtiny' +and 'avrisp2'. The default is 'usbtiny'. +.TP +\-device +Set the name of the target device. Choose one +of 'itsybitsy3v', 'itsybitsy5v' or 'uduino'. +.TP +\-hex +Specifies the hex file to load to the board. The default is the +currently installed version of Snek. +.TP +\-ubahex +Specifies the bootloader hex file to load to the board. The default is the +currently installed version of the bootloader for the target device. +.TP +\-ubaboot +Specifies the uba bootloader to use. The default is the +currently installed version of the bootloader. +.SH COMMANDS +.TP +load +Loads Snek to the device using ubaboot. This is the default command. +.TP +fuse +Sets the target fuse bits suitable for ubaboot usage. You must do this +before ubaboot will work on the target device, although you may do it +before or after loading the bootloader. You only need to do this once +per board. +.TP +boot +Load the uba bootloader on the target device. You only need to do this once +per board. +.TP +fuseboot +Sets the target fuse bits for ubaboot usage and then loads the +bootloader to the device. +.SH AUTHOR +Keith Packard diff --git a/ports/itsybitsy5v/snek-atmega32u4-install.in b/ports/itsybitsy5v/snek-atmega32u4-install.in new file mode 100644 index 00000000..3c3e71db --- /dev/null +++ b/ports/itsybitsy5v/snek-atmega32u4-install.in @@ -0,0 +1,106 @@ +#!/bin/sh + +SHAREDIR="@SHAREDIR@" + +DEVICE="" +UBABOOT="$SHAREDIR/ubaboot" + +action="load" + +ISP=usbtiny + +mode=arg + +verify="" + +for i in "$@"; do + case "$mode" in + arg) + case "$i" in + load|fuse|boot|fuseboot) + action="$i" + ;; + -isp|--isp) + mode=isp + ;; + -device|--device) + mode=device + ;; + -hex|--hex) + mode=hex + ;; + -ubahex|--ubahex) + mode=ubahex + ;; + -ubaboot|--ubaboot) + mode=ubaboot + ;; + -quick|--quick) + verify="-V" + ;; + *) + cat 1>&2 <.hex] + [-ubahex ubaboot-.hex] + [-ubaboot ubaboot.py] + [-quick] + {load|fuse|boot|fuseboot} +EOF + echo "" 1>&2 + exit 1 + ;; + esac + ;; + isp) + ISP="$i" + mode=arg + ;; + device) + DEVICE="$i" + SNEKHEX="$SHAREDIR/snek-$DEVICE-@SNEK_VERSION@.hex" + UBAHEX="$SHAREDIR/ubaboot-$DEVICE.hex" + mode=arg + ;; + hex) + SNEKHEX="$i" + mode=arg + ;; + ubahex) + UBAHEX="$i" + mode=arg + ;; + ubaboot) + UBABOOT="$i" + mode=arg + ;; + esac +done + +FUSES="-U hfuse:w:0x9e:m" + +case "$action" in + fuse) + avrdude -V -c $ISP -p m32u4 -u $FUSES + ;; + fuseboot) + case "${UBAHEX}" in + "") + echo "Please use either -device or -ubahex " 1>&2 + exit 1 + ;; + esac + avrdude -V -c $ISP -p m32u4 -u $FUSES && avrdude $verify -c $ISP -p m32u4 -U flash:w:"${UBAHEX}" + ;; + load) + case "${SNEKHEX}" in + "") + echo "Please use either -device or -hex " 1>&2 + exit 1 + ;; + esac + python "$UBABOOT" write "${SNEKHEX}" + ;; +esac diff --git a/ports/itsybitsy5v/snek-itsybitsy-install.1 b/ports/itsybitsy5v/snek-itsybitsy-install.1 deleted file mode 100644 index 802e7bf8..00000000 --- a/ports/itsybitsy5v/snek-itsybitsy-install.1 +++ /dev/null @@ -1,52 +0,0 @@ -.\" -.\" Copyright © 2019 Keith Packard -.\" -.\" This program is free software; you can redistribute it and/or modify -.\" it under the terms of the GNU General Public License as published by -.\" the Free Software Foundation, either version 3 of the License, or -.\" (at your option) any later version. -.\" -.\" This program is distributed in the hope that it will be useful, but -.\" WITHOUT ANY WARRANTY; without even the implied warranty of -.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -.\" General Public License for more details. -.\" -.TH SNEK-ITSYBITSY-INSTALL 1 "snek-itsybitsy-install" "" -.SH NAME -snek-itsybitsy-install \- Install Snek to Adafruit ItsyBitsy board -.SH SYNOPSIS -.B "snek-itsybitsy-install" [OPTION]... [COMMAND] -.SH DESCRIPTION -.I snek-itsybitsy-install -installs the Snek programming language on an Adafruit ItsyBitsy board -with an ATmega32u4. -.SH OPTIONS -.TP -\-isp -Specifies the programmer to use, common options are 'usbtiny' -and 'avrisp2'. The default is 'usbtiny'. -.TP -\-hex -Specifies the hex file to load to the board. The default is the -currently installed version of Snek. -.TP -\-3v -Use the 3v binary instead of the default 5v binary. -.SH COMMANDS -.TP -fuseload -Sets the target fuse bits for Snek usage and then loads Snek to the -device. This is the default command -.TP -load -Loads Snek to the device without first setting the fuse bits. Snek -will not work correctly if the fuse bits are not set correctly, so -only do this if the target has already had the fuse bits set correctly. -.TP -fuse -Sets the target fuse bits suitable for Snek usage. You must do this -before Snek will work on the target device, although you may do it -before or after loading the Snek system. You only need to do this once -per board. -.SH AUTHOR -Keith Packard diff --git a/ports/itsybitsy5v/snek-itsybitsy-install.in b/ports/itsybitsy5v/snek-itsybitsy-install.in deleted file mode 100644 index 3c9f8b4f..00000000 --- a/ports/itsybitsy5v/snek-itsybitsy-install.in +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/sh - -SHAREDIR="@SHAREDIR@" - -SNEKITSYBITSYBASE5V="$SHAREDIR/snek-itsybitsy5v" -SNEKITSYBITSYBASE3V="$SHAREDIR/snek-itsybitsy3v" -SNEKITSYBITSYREST="-@SNEK_VERSION@.hex" -SNEKITSYBITSY="$SNEKITSYBITSYBASE5V""$SNEKITSYBITSYREST" - -action="fuseload" - -ISP=usbtiny - -mode=arg - -verify="" - -for i in "$@"; do - case "$mode" in - arg) - case "$i" in - fuse|load|fuseload) - action="$i" - ;; - -isp|--isp) - mode=isp - ;; - -3v) - SNEKITSYBITSY="$SNEKITSYBITSYBASE3V""$SNEKITSYBITSYREST" - ;; - -5v) - SNEKITSYBITSY="$SNEKITSYBITSYBASE5V""$SNEKITSYBITSYREST" - ;; - -hex|--hex) - mode=hex - ;; - -quick) - verify="-V" - ;; - *) - echo "Usage: $0 {-isp usbtiny} {-isp avrisp2} {-3v} {-5v} {-hex snek-itsybitsy5v.hex} {fuseload|load|fuse}" 1>&2 - exit 1 - ;; - esac - ;; - isp) - ISP="$i" - mode=arg - ;; - hex) - SNEKITSYBITSY="$i" - mode=arg - ;; - esac -done - -FUSES="-U hfuse:w:0x99:m" - -case "$action" in - fuse) - avrdude -V -c $ISP -p m32u4 -u $FUSES - ;; - fuseload) - avrdude -V -c $ISP -p m32u4 -u $FUSES && avrdude $verify -c $ISP -p m32u4 -U flash:w:"${SNEKITSYBITSY}" - ;; - load) - avrdude $verify -c $ISP -p m32u4 -U flash:w:"${SNEKITSYBITSY}" - ;; -esac diff --git a/ports/lilypad-big/.gitignore b/ports/lilypad-big/.gitignore deleted file mode 100644 index 0447e4d6..00000000 --- a/ports/lilypad-big/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -snek-lilypad-big-*.elf -snek-lilypad-big-*.hex -snek-lilypad-big-*.map -snek-lilypad-big-install -snek-lilypad-big-install.1 diff --git a/ports/lilypad-big/Makefile b/ports/lilypad-big/Makefile deleted file mode 100644 index 43359c1f..00000000 --- a/ports/lilypad-big/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright © 2020 Keith Packard -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# - -SNEK_NO_DICT=1 -BOARD=lilypad-big -CBOARD=LilyPad-big -UBOARD=LILYPAD-BIG -PORT=/dev/ttyUSB0 -BAUD=57600 -CLOCK=8000000 -MCU=m328p - -SNEK_ATMEGA_BUILTINS_EXTRA = \ - snek-tone.builtin \ - snek-input.builtin - -include ../duemilanove-big/Makefile diff --git a/ports/lilypad/.gitignore b/ports/lilypad/.gitignore index d58e9963..d3cfcff6 100644 --- a/ports/lilypad/.gitignore +++ b/ports/lilypad/.gitignore @@ -2,4 +2,5 @@ snek-lilypad-*.elf snek-lilypad-*.hex snek-lilypad-*.map snek-lilypad-install +snek-lilypad-install.in snek-lilypad-install.1 diff --git a/ports/lilypad/Makefile b/ports/lilypad/Makefile index 84cdbcbe..42752a29 100644 --- a/ports/lilypad/Makefile +++ b/ports/lilypad/Makefile @@ -12,7 +12,6 @@ # General Public License for more details. # -SNEK_NO_DICT=1 BOARD=lilypad CBOARD=LilyPad UBOARD=LILYPAD @@ -21,7 +20,4 @@ BAUD=57600 CLOCK=8000000 MCU=m328p -SNEK_ATMEGA_BUILTINS_EXTRA = \ - snek-tone.builtin - include ../duemilanove/Makefile diff --git a/ports/mega/Makefile b/ports/mega/Makefile index 57630309..18ebe862 100644 --- a/ports/mega/Makefile +++ b/ports/mega/Makefile @@ -47,7 +47,7 @@ ELF=$(BASE).elf HEX=$(BASE).hex MAP=$(BASE).map CC=avr-gcc -CFLAGS=-Os -DF_CPU=16000000UL -mmcu=atmega2560 -I. -I$(SNEK_LOCAL_VPATH) -g -fno-jump-tables $(SNEK_CFLAGS) -mcall-prologues -Waddr-space-convert +CFLAGS=-DF_CPU=16000000UL -mmcu=atmega2560 -I. -I$(SNEK_LOCAL_VPATH) -g $(SNEK_CFLAGS) $(OPT) -Waddr-space-convert LDFLAGS=$(SNEK_LDFLAGS) \ -Wl,-uvfprintf -lprintf_flt -lm \ -Wl,-Map=$(MAP) @@ -61,7 +61,7 @@ $(HEX): $(ELF) $(ELF): $(SNEK_OBJ) $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) - @gawk '/__data_load_end/{printf("ROM used: %d bytes\n", strtonum($$1)); }' $(MAP) + @gawk '/__data_load_end/{printf("$(BASE) ROM: %d bytes\n", strtonum($$1)); }' $(MAP) snek-mega-install: snek-mega-install.in $(SNEK_SED) $^ > $@ diff --git a/ports/mega/snek-mega.c b/ports/mega/snek-mega.c index 6be656a1..d2b8c086 100644 --- a/ports/mega/snek-mega.c +++ b/ports/mega/snek-mega.c @@ -162,7 +162,7 @@ snek_builtin_reset(void) typedef volatile uint8_t vuint8_t; -static vuint8_t * PROGMEM const port_to_mode_PGM[] = { +static vuint8_t * CONST port_to_mode_PGM[] = { NOT_A_PORT, &DDRA, &DDRB, @@ -178,7 +178,7 @@ static vuint8_t * PROGMEM const port_to_mode_PGM[] = { &DDRL, }; -static vuint8_t * PROGMEM const port_to_output_PGM[] = { +static vuint8_t * CONST port_to_output_PGM[] = { NOT_A_PORT, &PORTA, &PORTB, @@ -194,7 +194,7 @@ static vuint8_t * PROGMEM const port_to_output_PGM[] = { &PORTL, }; -static vuint8_t * PROGMEM const port_to_input_PGM[] = { +static vuint8_t * CONST port_to_input_PGM[] = { NOT_A_PIN, &PINA, &PINB, @@ -210,7 +210,7 @@ static vuint8_t * PROGMEM const port_to_input_PGM[] = { &PINL, }; -const uint8_t PROGMEM digital_pin_to_port_PGM[] = { +CONST uint8_t digital_pin_to_port_PGM[] = { // PORTLIST // ------------------------------------------- PE , // PE 0 ** 0 ** USART0_RX @@ -285,7 +285,7 @@ const uint8_t PROGMEM digital_pin_to_port_PGM[] = { PK , // PK 7 ** 69 ** A15 }; -const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { +CONST uint8_t digital_pin_to_bit_mask_PGM[] = { // PIN IN PORT // ------------------------------------------- _BV( 0 ) , // PE 0 ** 0 ** USART0_RX @@ -363,28 +363,28 @@ const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { static volatile uint8_t * ddr_reg(uint8_t pin) { - return pgm_read_ptr(&port_to_mode_PGM[pgm_read_byte(&digital_pin_to_port_PGM[pin])]); + return port_to_mode_PGM[digital_pin_to_port_PGM[pin]]; } static volatile uint8_t * pin_reg(uint8_t pin) { - return pgm_read_ptr(&port_to_input_PGM[pgm_read_byte(&digital_pin_to_port_PGM[pin])]); + return port_to_input_PGM[digital_pin_to_port_PGM[pin]]; } static volatile uint8_t * port_reg(uint8_t pin) { - return pgm_read_ptr(&port_to_output_PGM[pgm_read_byte(&digital_pin_to_port_PGM[pin])]); + return port_to_output_PGM[digital_pin_to_port_PGM[pin]]; } static uint8_t bit(uint8_t pin) { - return pgm_read_byte(&digital_pin_to_bit_mask_PGM[pin]); + return digital_pin_to_bit_mask_PGM[pin]; } -static volatile uint8_t * const PROGMEM ocr_reg_addrs[NUM_PIN] = { +static volatile uint8_t * CONST ocr_reg_addrs[NUM_PIN] = { [2] = &OCR3BL, [3] = &OCR3CL, [4] = &OCR0B, @@ -404,7 +404,7 @@ static volatile uint8_t * const PROGMEM ocr_reg_addrs[NUM_PIN] = { static volatile uint8_t * ocr_reg(uint8_t pin) { - return (volatile uint8_t *) pgm_read_ptr(&ocr_reg_addrs[pin]); + return ocr_reg_addrs[pin]; } static bool @@ -413,7 +413,7 @@ has_pwm(uint8_t p) return ocr_reg(p) != NULL; } -static volatile uint8_t * const PROGMEM tcc_reg_addrs[] = { +static volatile uint8_t * CONST tcc_reg_addrs[] = { [2] = &TCCR3A, [3] = &TCCR3A, [4] = &TCCR0A, @@ -433,10 +433,10 @@ static volatile uint8_t * const PROGMEM tcc_reg_addrs[] = { static volatile uint8_t * tcc_reg(uint8_t pin) { - return (volatile uint8_t *) pgm_read_ptr(&tcc_reg_addrs[pin]); + return tcc_reg_addrs[pin]; } -static uint8_t const PROGMEM tcc_vals[] = { +static uint8_t CONST tcc_vals[] = { [2] = (0 << COM3B0) | (1 << COM3B1), [3] = (0 << COM3C0) | (1 << COM3C1), [4] = (0 << COM0B0) | (1 << COM0B1), @@ -457,7 +457,7 @@ static uint8_t const PROGMEM tcc_vals[] = { static uint8_t tcc_val(uint8_t pin) { - return (uint8_t) pgm_read_byte(&tcc_vals[pin]); + return tcc_vals[pin]; } static bool diff --git a/ports/nano-every/Makefile b/ports/nano-every/Makefile index 125d7662..70f85c1e 100644 --- a/ports/nano-every/Makefile +++ b/ports/nano-every/Makefile @@ -19,6 +19,8 @@ CBOARD?=NanoEvery UBOARD?=NANOEVERY PORT?=/dev/ttyACM0 +SNEK_ATMEGA_STORE_SRC = snek-atmega-flash.c + include $(SNEK_ATMEGA)/snek-atmega.defs SNEK_LOCAL_VPATH = $(SNEK_ATMEGA) @@ -26,7 +28,6 @@ SNEK_LOCAL_VPATH = $(SNEK_ATMEGA) SNEK_LOCAL_SRC = \ snek-pow.c \ snek-nano-every.c \ - snek-input.c \ $(SNEK_ATMEGA_MATH_SRC) \ $(SNEK_ATMEGA_SRC) @@ -36,18 +37,20 @@ SNEK_LOCAL_INC = \ SNEK_LOCAL_BUILTINS = \ $(SNEK_ATMEGA_BUILTINS) \ - snek-input.builtin \ - snek-math.builtin \ + snek-math-small.builtin \ snek-nano-every.builtin include $(SNEK_ROOT)/snek-install.defs AVR_ROOT=$(HOME)/misc/arduino/arduino-1.8.13/hardware/tools/avr +ATMEGA_CODE_SIZE=0xb000 + SNEK_NANO_EVERY_SED=$(SNEK_SED) \ -e 's;@BOARD@;$(BOARD);g' \ -e 's;@UBOARD@;$(UBOARD);g' \ -e 's;@CBOARD@;$(CBOARD);g' \ + -e 's;@ATMEGA_CODE_SIZE@;$(ATMEGA_CODE_SIZE);g' \ -e 's;@PORT@;$(PORT);g' \ -e 's;@AVR_ROOT@;$(AVR_ROOT);g' @@ -57,13 +60,25 @@ BASE=snek-$(BOARD)-$(SNEK_VERSION) ELF=$(BASE).elf HEX=$(BASE).hex MAP=$(BASE).map -CC=$(AVR_ROOT)/bin/avr-gcc - -OPT=-Os -frename-registers -funsigned-char -fno-jump-tables -mcall-prologues +CC=avr-gcc + +MCU=atmega4809 +AVR_LIBC_ROOT=/opt/avr-libc +AVR_LIBC_LIB=$(AVR_LIBC_ROOT)/avr/lib/$(shell avr-gcc -print-multi-os-directory -mmcu=$(MCU)) +AVR_LIBC_INCLUDE=$(AVR_LIBC_ROOT)/avr/include +CRT0=crt$(MCU).o + +CFLAGS=-DF_CPU=20000000UL \ + -mmcu=$(MCU) \ + -isystem$(AVR_LIBC_INCLUDE) -L$(AVR_LIBC_LIB) \ + -I. -I$(SNEK_LOCAL_VPATH) -g \ + $(SNEK_CFLAGS) \ + $(OPT) \ + -Waddr-space-convert -CFLAGS=$(OPT) -DF_CPU=20000000UL -mmcu=atmega4809 -I. -I$(SNEK_LOCAL_VPATH) -g $(SNEK_CFLAGS) -Waddr-space-convert LDFLAGS=$(SNEK_LDFLAGS) \ - -Wl,-uvfprintf -lprintf_flt -lm \ + -lm \ + -Wl,--defsym,__TEXT_REGION_LENGTH__=$(ATMEGA_CODE_SIZE) \ -Wl,-Map=$(MAP) all: $(HEX) snek-$(BOARD)-install snek-$(BOARD)-install.1 snek-$(BOARD)-reset-port @@ -71,16 +86,22 @@ all: $(HEX) snek-$(BOARD)-install snek-$(BOARD)-install.1 snek-$(BOARD)-reset-po $(HEX): $(ELF) avr-objcopy -O ihex -R .eeprom $^ $@ -$(ELF): $(SNEK_OBJ) - $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) - @gawk '/__data_load_end/{printf("ROM used: %d bytes\n", strtonum($$1)); }' $(MAP) +$(ELF): $(SNEK_OBJ) $(CRT0) + $(CC) $(CFLAGS) -o $@ $(SNEK_OBJ) $(LDFLAGS) + @gawk '/__data_load_end/{printf("$(BASE) ROM: %d bytes\n", strtonum($$1)); }' $(MAP) + +$(CRT0): $(AVR_LIBC_LIB)/$(CRT0) + cp $^ $@ snek-$(BOARD)-install: snek-nano-every-install.in $(SNEK_NANO_EVERY_SED) $^ > $@ chmod +x $@ load: $(HEX) snek-$(BOARD)-install snek-$(BOARD)-reset-port - ./snek-$(BOARD)-install -reset ./snek-$(BOARD)-reset-port -hex $(HEX) + ./snek-$(BOARD)-install -reset ./snek-$(BOARD)-reset-port -hex $(HEX) load + +fuseload: $(HEX) snek-$(BOARD)-install snek-$(BOARD)-reset-port + ./snek-$(BOARD)-install -reset ./snek-$(BOARD)-reset-port -hex $(HEX) fuseload snek-$(BOARD)-install.1: snek-nano-every-install.1.in $(SNEK_NANO_EVERY_SED) $^ > $@ diff --git a/ports/nano-every/snek-nano-every-install.in b/ports/nano-every/snek-nano-every-install.in index b42627d4..7a4ebd5c 100644 --- a/ports/nano-every/snek-nano-every-install.in +++ b/ports/nano-every/snek-nano-every-install.in @@ -5,19 +5,27 @@ SHAREDIR="@SHAREDIR@" SNEKDUINO="$SHAREDIR/snek-@BOARD@-@SNEK_VERSION@.hex" AVR_ROOT=@AVR_ROOT@ -AVRDUDE="$AVR_ROOT/bin/avrdude -C$AVR_ROOT/etc/avrdude.conf -v" +AVRDUDE="$AVR_ROOT/bin/avrdude -C$AVR_ROOT/etc/avrdude.conf" RESET="$SHAREDIR/snek-@BOARD@-reset-port" action="default" PORT="@PORT@" +# Convert end of code from bytes to flash pages (256 byte units) +ATMEGA_CODE_SIZE=`echo "@ATMEGA_CODE_SIZE@" | sed 's/00$//'` + mode=arg +action=load + for i in "$@"; do case "$mode" in arg) case "$i" in + load|fuse|fuseload) + action="$i" + ;; -hex|--hex) mode=hex ;; @@ -49,5 +57,19 @@ done echo "$RESET" "$PORT" "$RESET" "$PORT" -echo $AVRDUDE -P $PORT -c jtag2updi -b 115200 -p atmega4809 -e -D -U flash:w:"${SNEKDUINO}" -Ufuse2:w:0x02:m -Ufuse5:w:0xC9:m -Ufuse8:w:0x00:m -$AVRDUDE -P $PORT -c jtag2updi -b 115200 -p atmega4809 -e -D -U flash:w:"${SNEKDUINO}" -Ufuse2:w:0x02:m -Ufuse5:w:0xC9:m -Ufuse8:w:0x00:m + +fuse="-Ufuse2:w:0x02:m -Ufuse5:w:0xC9:m -Ufuse8:w:$ATMEGA_CODE_SIZE:m -Ufuse7:w:$ATMEGA_CODE_SIZE:m" +case $action in + fuse) + echo $AVRDUDE -P $PORT -c jtag2updi -b 115200 -p atmega4809 "$fuse" + $AVRDUDE -P $PORT -c jtag2updi -b 115200 -p atmega4809 "$fuse" + ;; + load) + echo $AVRDUDE -P $PORT -c jtag2updi -b 115200 -p atmega4809 -U flash:w:"${SNEKDUINO}" + $AVRDUDE -P $PORT -c jtag2updi -b 115200 -p atmega4809 -U flash:w:"${SNEKDUINO}" + ;; + fuseload) + echo $AVRDUDE -P $PORT -c jtag2updi -b 115200 -p atmega4809 $fuse -U flash:w:"${SNEKDUINO}" + $AVRDUDE -P $PORT -c jtag2updi -b 115200 -p atmega4809 $fuse -U flash:w:"${SNEKDUINO}" + ;; +esac diff --git a/ports/nano-every/snek-nano-every.builtin b/ports/nano-every/snek-nano-every.builtin index b7b929c4..4bcd3469 100644 --- a/ports/nano-every/snek-nano-every.builtin +++ b/ports/nano-every/snek-nano-every.builtin @@ -25,6 +25,7 @@ D10, -2, 10 D11, -2, 11 D12, -2, 12 D13, -2, 13 +LED, -2, 13 A0, -2, 14 A1, -2, 15 A2, -2, 16 @@ -37,3 +38,4 @@ A7, -2, 21 #include #define SNEK_POOL 3584 #define SNEK_MAX_TOKEN 63 +#define SNEK_NEED_UART_WAIT_QUEUED diff --git a/ports/nano-every/snek-nano-every.c b/ports/nano-every/snek-nano-every.c index 9476b96a..3ae4d55a 100644 --- a/ports/nano-every/snek-nano-every.c +++ b/ports/nano-every/snek-nano-every.c @@ -35,13 +35,17 @@ static inline uint8_t pin_bit(uint8_t p) return (p & 7); } +#ifndef ADC_REFSEL_0_bm +#define ADC_REFSEL_0_bm ADC_REFSEL0_bm +#endif + static void port_init(void) { uint8_t p; /* Enable ADC */ - ADC0_CTRLC = (ADC_SAMPCAP_bm | ADC_REFSEL0_bm | ADC_PRESC_DIV16_gc); + ADC0_CTRLC = (ADC_SAMPCAP_bm | ADC_REFSEL_0_bm | ADC_PRESC_DIV16_gc); ADC0_CTRLA = ADC_ENABLE_bm; /* TCA0 */ @@ -76,6 +80,8 @@ FILE snek_duino_file = FDEV_SETUP_STREAM(snek_uart_putchar, snek_eeprom_getchar, int __attribute__((OS_main)) main (void) { + uint8_t ctrla = CPUINT.CTRLA | 0x40; + _PROTECTED_WRITE(CPUINT.CTRLA, ctrla); _PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, 0); stderr = stdout = stdin = &snek_duino_file; snek_uart_init(); @@ -104,7 +110,7 @@ snek_builtin_reset(void) typedef volatile uint8_t vuint8_t; -static VPORT_t * PROGMEM const port_to_vport_PGM[] = { +static VPORT_t * CONST port_to_vport_PGM[] = { NOT_A_PORT, &VPORTA, &VPORTB, @@ -114,7 +120,7 @@ static VPORT_t * PROGMEM const port_to_vport_PGM[] = { &VPORTF, }; -const uint8_t PROGMEM digital_pin_to_port_PGM[] = { +static CONST uint8_t digital_pin_to_port_PGM[] = { // PORTLIST // ------------------------------------------- PB , // PB 4 ** 0 ** USART0_RX @@ -141,7 +147,7 @@ const uint8_t PROGMEM digital_pin_to_port_PGM[] = { PD , // PD 5 ** 21 ** A7 }; -const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { +static CONST uint8_t digital_pin_to_bit_mask_PGM[] = { // PIN IN PORT // ------------------------------------------- _BV(4) , // PB 4 ** 0 ** USART0_RX @@ -171,7 +177,7 @@ const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { static VPORT_t * vport(uint8_t pin) { - return pgm_read_ptr(&(port_to_vport_PGM[pgm_read_byte(&digital_pin_to_port_PGM[pin])])); + return port_to_vport_PGM[digital_pin_to_port_PGM[pin]]; } static volatile uint8_t * @@ -195,10 +201,10 @@ port_reg(uint8_t pin) static uint8_t bit(uint8_t pin) { - return pgm_read_byte(&digital_pin_to_bit_mask_PGM[pin]); + return digital_pin_to_bit_mask_PGM[pin]; } -static volatile uint16_t * const PROGMEM ccmp_reg_addrs[NUM_PIN] = { +static volatile uint16_t * CONST ccmp_reg_addrs[NUM_PIN] = { [3] = &TCB1_CCMP, [5] = &TCA0_SINGLE_CMP2, [6] = &TCB0_CCMP, @@ -208,7 +214,7 @@ static volatile uint16_t * const PROGMEM ccmp_reg_addrs[NUM_PIN] = { static volatile uint16_t * ccmp_reg(uint8_t pin) { - return (volatile uint16_t *) pgm_read_ptr(&ccmp_reg_addrs[pin]); + return ccmp_reg_addrs[pin]; } static bool @@ -217,7 +223,7 @@ has_pwm(uint8_t p) return ccmp_reg(p) != NULL; } -static volatile uint8_t * const PROGMEM tcc_reg_addrs[NUM_PIN] = { +static volatile uint8_t * CONST tcc_reg_addrs[NUM_PIN] = { [3] = &TCB1_CTRLB, [5] = &TCA0_SINGLE_CTRLB, [6] = &TCB0_CTRLB, @@ -227,10 +233,10 @@ static volatile uint8_t * const PROGMEM tcc_reg_addrs[NUM_PIN] = { static volatile uint8_t * tcc_reg(uint8_t pin) { - return (volatile uint8_t *) pgm_read_ptr(&tcc_reg_addrs[pin]); + return tcc_reg_addrs[pin]; } -static uint8_t const PROGMEM tcc_vals[NUM_PIN] = { +static uint8_t CONST tcc_vals[NUM_PIN] = { [3] = TCB_CCMPEN_bm, [5] = TCA_SINGLE_CMP2EN_bm, [6] = TCB_CCMPEN_bm, @@ -241,7 +247,7 @@ static uint8_t const PROGMEM tcc_vals[NUM_PIN] = { static uint8_t tcc_val(uint8_t pin) { - return (uint8_t) pgm_read_byte(&tcc_vals[pin]); + return tcc_vals[pin]; } static bool @@ -413,7 +419,7 @@ snek_builtin_pullup(snek_poly_t a) return SNEK_NULL; } -static uint8_t const PROGMEM mux_pos_vals[] = { +static uint8_t CONST mux_pos_vals[] = { [0] = ADC_MUXPOS_AIN3_gc, [1] = ADC_MUXPOS_AIN2_gc, [2] = ADC_MUXPOS_AIN1_gc, @@ -426,7 +432,7 @@ static uint8_t const PROGMEM mux_pos_vals[] = { static uint8_t mux_pos(uint8_t a_pin) { - return (uint8_t) pgm_read_byte(&mux_pos_vals[a_pin]); + return mux_pos_vals[a_pin]; } snek_poly_t diff --git a/ports/narrow-1284/Makefile b/ports/narrow-1284/Makefile index c0ad653f..920638e0 100644 --- a/ports/narrow-1284/Makefile +++ b/ports/narrow-1284/Makefile @@ -45,7 +45,7 @@ ELF=$(BASE).elf HEX=$(BASE).hex MAP=$(BASE).map CC=avr-gcc -CFLAGS=-Os -DF_CPU=16000000UL -mmcu=atmega1284 -I. -I$(SNEK_LOCAL_VPATH) -g -fno-jump-tables $(SNEK_CFLAGS) -mcall-prologues -Waddr-space-convert +CFLAGS=-DF_CPU=16000000UL -mmcu=atmega1284 -I. -I$(SNEK_LOCAL_VPATH) -g -fno-jump-tables $(SNEK_CFLAGS) $(OPT) -Waddr-space-convert LDFLAGS=$(SNEK_LDFLAGS) \ -Wl,-uvfprintf -lprintf_flt -lm \ -Wl,-Map=$(MAP) @@ -59,7 +59,7 @@ $(HEX): $(ELF) $(ELF): $(SNEK_OBJ) $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) - @gawk '/__data_load_end/{printf("ROM used: %d bytes\n", strtonum($$1)); }' $(MAP) + @gawk '/__data_load_end/{printf("$(BASE) ROM: %d bytes\n", strtonum($$1)); }' $(MAP) snek-narrow-1284-install: snek-narrow-1284-install.in $(SNEK_SED) $^ > $@ diff --git a/ports/narrow-1284/snek-narrow-1284-math.builtin b/ports/narrow-1284/snek-narrow-1284-math.builtin index 2fa0067f..c71f5c99 100644 --- a/ports/narrow-1284/snek-narrow-1284-math.builtin +++ b/ports/narrow-1284/snek-narrow-1284-math.builtin @@ -41,6 +41,7 @@ math.exp, 1 math.log, 1 math.log10, 1 math.pow, 2 +pow, 2, =math.pow # # Trigonometric functions # @@ -72,5 +73,5 @@ math.tanh, 1 math.pi, -2, 3.141592653589793 math.e, -2, 2.718281828459045 math.tau, -2, 6.283185307179586 -math.inf, -2, INFINITY -math.nan, -2, NAN +math.inf, -2, (snek_poly_t)(float)INFINITY +math.nan, -2, (snek_poly_t)(float)NAN diff --git a/ports/narrow-1284/snek-narrow-1284.c b/ports/narrow-1284/snek-narrow-1284.c index 6827c935..fb8a1a36 100644 --- a/ports/narrow-1284/snek-narrow-1284.c +++ b/ports/narrow-1284/snek-narrow-1284.c @@ -161,14 +161,14 @@ has_pwm(uint8_t p) return pwm_pins & (1 << p); } -static volatile uint8_t * const PROGMEM ocr8_reg_addrs[] = { +static volatile uint8_t * CONST ocr8_reg_addrs[] = { [3] = &OCR0A, [4] = &OCR0B, [14] = &OCR2B, [15] = &OCR2A, }; -static volatile uint16_t * const PROGMEM ocr16_reg_addrs[] = { +static volatile uint16_t * CONST ocr16_reg_addrs[] = { [6] = &OCR3A, [7] = &OCR3B, [12] = &OCR1B, @@ -177,15 +177,15 @@ static volatile uint16_t * const PROGMEM ocr16_reg_addrs[] = { static volatile uint8_t * ocr8_reg(uint8_t pin) { - return (volatile uint8_t *) pgm_read_word(&ocr8_reg_addrs[pin]); + return ocr8_reg_addrs[pin]; } static volatile uint16_t * ocr16_reg(uint8_t pin) { - return (volatile uint16_t *) pgm_read_word(&ocr16_reg_addrs[pin]); + return ocr16_reg_addrs[pin]; } -static volatile uint8_t * const PROGMEM tcc_reg_addrs[] = { +static volatile uint8_t * CONST tcc_reg_addrs[] = { [3] = &TCCR0A, [4] = &TCCR0B, [6] = &TCCR3A, @@ -198,10 +198,10 @@ static volatile uint8_t * const PROGMEM tcc_reg_addrs[] = { static volatile uint8_t * tcc_reg(uint8_t pin) { - return (volatile uint8_t *) pgm_read_word(&tcc_reg_addrs[pin]); + return tcc_reg_addrs[pin]; } -static uint8_t const PROGMEM tcc_val_addrs[] = { +static uint8_t CONST tcc_val_addrs[] = { [3] = 1 << COM0A1, [4] = 1 << COM0B1, [6] = 1 << COM3A1, @@ -215,7 +215,7 @@ static uint8_t const PROGMEM tcc_val_addrs[] = { static uint8_t tcc_val(uint8_t pin) { - return (uint8_t) pgm_read_byte(&tcc_val_addrs[pin]); + return tcc_val_addrs[pin]; } static void diff --git a/ports/posix/snek-posix.h b/ports/posix/snek-posix.h index f214a052..ffdd4ba8 100644 --- a/ports/posix/snek-posix.h +++ b/ports/posix/snek-posix.h @@ -26,6 +26,8 @@ int snek_getc(FILE *input); #define SNEK_GETC() snek_getc(snek_posix_input) +#define CONST const + #define SNEK_DEBUG 1 #endif /* _SNEK_POSIX_H_ */ diff --git a/ports/uduino/Makefile b/ports/uduino/Makefile index 9770600e..d260d674 100644 --- a/ports/uduino/Makefile +++ b/ports/uduino/Makefile @@ -34,34 +34,30 @@ SNEK_LOCAL_BUILTINS = \ include $(SNEK_ROOT)/snek-install.defs -all: $(ELF) $(HEX) snek-uduino-install +all: $(ELF) $(HEX) $(PROG): Makefile $(SNEK_OBJ) $(CC) $(CFLAGS) -o $@ $(SNEK_OBJ) $(LDFLAGS) - @gawk '/__data_load_end/{printf("ROM used: %d bytes\n", strtonum($$1)); }' $(MAP) - -snek-uduino-install: snek-uduino-install.in - $(SNEK_SED) $^ > $@ - chmod +x $@ + @gawk '/__data_load_end/{printf("$(BASE) ROM: %d bytes\n", strtonum($$1)); }' $(MAP) install:: $(HEX) install -d $(DESTDIR)$(SHAREDIR) install -m 0644 $(HEX) $(DESTDIR)$(SHAREDIR) -install:: snek-uduino-install snek-uduino-install.1 - install -d $(DESTDIR)$(BINDIR) - install snek-uduino-install $(DESTDIR)$(BINDIR) - install -d $(DESTDIR)$(MANDIR)/man1 - install -m 0644 snek-uduino-install.1 $(DESTDIR)$(MANDIR)/man1 - clean:: - rm -f snek-uduino-install rm -f *.hex *.elf *.map rm -f ao-product.h uninstall:: -ISP=avrisp2 +ISP=usbtiny + +UBANAME=$(shell echo $(PROGNAME) | sed 's/snek/ubaboot/') +UBAHEX=../../ubaboot/$(UBANAME).hex +UBABOOT=../../ubaboot/ubaboot.py + +load: all $(UBABOOT) + ../itsybitsy5v/snek-atmega32u4-install -hex $(HEX) -ubaboot $(UBABOOT) load -load: $(HEX) snek-uduino-install - ./snek-uduino-install -quick -isp $(ISP) -hex $(HEX) load +fuseboot: $(UBAHEX) $(UBABOOT) + ../itsybitsy5v/snek-atmega32u4-install -isp $(ISP) -ubahex $(UBAHEX) fuseboot diff --git a/ports/uduino/ao-pins.h b/ports/uduino/ao-pins.h index 55cecc27..fb177e23 100644 --- a/ports/uduino/ao-pins.h +++ b/ports/uduino/ao-pins.h @@ -23,9 +23,6 @@ #define HAS_BEEP 0 #define AO_FIFO_SIZE 64 -#define AVR_VCC_5V 1 -#define AVR_VCC_3V3 0 - #define SNEK_IO_GETC(file) ao_usb_getc() #define SNEK_GETC() (snek_avr_file.get(stdin)) #define fflush(x) ao_usb_flush(x) diff --git a/ports/uduino/snek-uduino-install.1 b/ports/uduino/snek-uduino-install.1 deleted file mode 100644 index 802e7bf8..00000000 --- a/ports/uduino/snek-uduino-install.1 +++ /dev/null @@ -1,52 +0,0 @@ -.\" -.\" Copyright © 2019 Keith Packard -.\" -.\" This program is free software; you can redistribute it and/or modify -.\" it under the terms of the GNU General Public License as published by -.\" the Free Software Foundation, either version 3 of the License, or -.\" (at your option) any later version. -.\" -.\" This program is distributed in the hope that it will be useful, but -.\" WITHOUT ANY WARRANTY; without even the implied warranty of -.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -.\" General Public License for more details. -.\" -.TH SNEK-ITSYBITSY-INSTALL 1 "snek-itsybitsy-install" "" -.SH NAME -snek-itsybitsy-install \- Install Snek to Adafruit ItsyBitsy board -.SH SYNOPSIS -.B "snek-itsybitsy-install" [OPTION]... [COMMAND] -.SH DESCRIPTION -.I snek-itsybitsy-install -installs the Snek programming language on an Adafruit ItsyBitsy board -with an ATmega32u4. -.SH OPTIONS -.TP -\-isp -Specifies the programmer to use, common options are 'usbtiny' -and 'avrisp2'. The default is 'usbtiny'. -.TP -\-hex -Specifies the hex file to load to the board. The default is the -currently installed version of Snek. -.TP -\-3v -Use the 3v binary instead of the default 5v binary. -.SH COMMANDS -.TP -fuseload -Sets the target fuse bits for Snek usage and then loads Snek to the -device. This is the default command -.TP -load -Loads Snek to the device without first setting the fuse bits. Snek -will not work correctly if the fuse bits are not set correctly, so -only do this if the target has already had the fuse bits set correctly. -.TP -fuse -Sets the target fuse bits suitable for Snek usage. You must do this -before Snek will work on the target device, although you may do it -before or after loading the Snek system. You only need to do this once -per board. -.SH AUTHOR -Keith Packard diff --git a/ports/uduino/snek-uduino-install.in b/ports/uduino/snek-uduino-install.in deleted file mode 100644 index 69fbbe12..00000000 --- a/ports/uduino/snek-uduino-install.in +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/sh - -SHAREDIR="@SHAREDIR@" - -SNEKUDUINOBASE="$SHAREDIR/snek-uduino" -SNEKUDUINOREST="-@SNEK_VERSION@.hex" -SNEKUDUINO="$SNEKUDUINOBASE""$SNEKUDUINOREST" - -action="fuseload" - -ISP=usbtiny - -mode=arg - -verify="" - -for i in "$@"; do - case "$mode" in - arg) - case "$i" in - fuse|load|fuseload) - action="$i" - ;; - -isp|--isp) - mode=isp - ;; - -hex|--hex) - mode=hex - ;; - -quick) - verify="-V" - ;; - *) - echo "Usage: $0 {-isp usbtiny} {-isp avrisp2} {-hex snek-uduino.hex} {fuseload|load|fuse}" 1>&2 - exit 1 - ;; - esac - ;; - isp) - ISP="$i" - mode=arg - ;; - hex) - SNEKUDUINO="$i" - mode=arg - ;; - esac -done - -FUSES="-U lfuse:w:0xff:m -U hfuse:w:0x91:m -U efuse:w:0xfd:m" - -case "$action" in - fuse) - avrdude -V -c $ISP -p m32u4 -u $FUSES - ;; - fuseload) - avrdude -V -c $ISP -p m32u4 -u $FUSES && avrdude $verify -c $ISP -p m32u4 -U flash:w:"${SNEKUDUINO}" - ;; - load) - avrdude $verify -c $ISP -p m32u4 -U flash:w:"${SNEKUDUINO}" - ;; -esac diff --git a/ports/uno-big/.gitignore b/ports/uno-big/.gitignore deleted file mode 100644 index 5f7b8319..00000000 --- a/ports/uno-big/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -snek-uno-big-*.elf -snek-uno-big-*.map -snek-uno-big-*.hex -snek-uno-big-install -snek-uno-big-install.1 diff --git a/ports/uno-big/Makefile b/ports/uno-big/Makefile deleted file mode 100644 index 2a399945..00000000 --- a/ports/uno-big/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# -# Copyright © 2020 Keith Packard -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# - -BOARD?=uno-big -CBOARD?=Uno-big -UBOARD?=UNO-BIG -PORT?=/dev/ttyACM0 -MCU?=m328p - -include ../duemilanove-big/Makefile diff --git a/snek-atof.c b/snek-atof.c index d9dc8f01..8dd16838 100644 --- a/snek-atof.c +++ b/snek-atof.c @@ -35,13 +35,6 @@ #include /* INFINITY, NAN */ #include -#ifdef AVR -#define float double -#include -#else -#define __flash -#define pgm_read_dword(x) (*x) -#endif #include /* Only GCC 4.2 calls the library function to convert an unsigned long @@ -49,10 +42,10 @@ conversion along with a large inline code to correct the result. */ extern float __floatunsisf (unsigned long); -static const __flash float pwr_p10 [6] = { +static CONST float pwr_p10 [6] = { 1e+32, 1e+16, 1e+8, 1e+4, 1e+2, 1e+1, }; -static const __flash float pwr_m10 [6] = { +static CONST float pwr_m10 [6] = { 1e-32, 1e-16, 1e-8, 1e-4, 1e-2, 1e-1, }; @@ -168,7 +161,7 @@ atoff (const char * nptr) if (x.flt != 0) { int pwr; - const __flash float *fptr; + CONST float *fptr; if (exp < 0) { fptr = pwr_m10; diff --git a/snek-builtin.py b/snek-builtin.py index c163ab04..64a33ae2 100644 --- a/snek-builtin.py +++ b/snek-builtin.py @@ -199,7 +199,7 @@ def set_ids(): def dump_names(fp): fprint( - "static const uint8_t SNEK_BUILTIN_NAMES_DECLARE(snek_builtin_names)[] = {", + "static CONST uint8_t snek_builtin_names[] = {", file=fp, ) total = 0 @@ -276,7 +276,7 @@ def dump_decls(fp): def dump_builtins(fp): - fprint("const snek_builtin_t SNEK_BUILTIN_DECLARE(snek_builtins)[] = {", file=fp) + fprint("CONST snek_builtin_t snek_builtins[] = {", file=fp) for name in sorted(builtins): if name.keyword: @@ -336,9 +336,6 @@ def builtin_main(): fprint("#ifdef SNEK_BUILTIN_DATA", file=fp) fprint("#undef SNEK_BUILTIN_DATA", file=fp) - fprint("#ifndef SNEK_BUILTIN_NAMES_DECLARE", file=fp) - fprint("#define SNEK_BUILTIN_NAMES_DECLARE(n) n", file=fp) - fprint("#endif", file=fp) set_ids() @@ -348,10 +345,6 @@ def builtin_main(): max_formals = max_args() - fprint("#ifndef SNEK_BUILTIN_DECLARE", file=fp) - fprint("#define SNEK_BUILTIN_DECLARE(n) n", file=fp) - fprint("#endif", file=fp) - dump_builtins(fp) fprint(file=fp) @@ -369,14 +362,6 @@ def builtin_main(): dump_init(fp) - fprint("#ifndef SNEK_BUILTIN_NFORMAL", file=fp) - fprint("#define SNEK_BUILTIN_NFORMAL(b) ((b)->nformal)", file=fp) - fprint("#define SNEK_BUILTIN_FUNCV(b) ((b)->funcv)", file=fp) - for f in range(max_formals + 1): - fprint("#define SNEK_BUILTIN_FUNC%d(b) ((b)->func%d)" % (f, f), file=fp) - fprint("#define SNEK_BUILTIN_VALUE(b) ((b)->value)", file=fp) - fprint("#endif", file=fp) - dump_cpp(fp) fprint("#endif /* SNEK_BUILTIN_DECLS */", file=fp) diff --git a/snek-code.c b/snek-code.c index 772c3b02..f173a0bc 100644 --- a/snek-code.c +++ b/snek-code.c @@ -178,7 +178,7 @@ snek_code_add_number(float number) * Add an immediate string to the current bytecode */ void -snek_code_add_string(char *string) +snek_code_add_string(const char *string) { snek_offset_t s; @@ -384,7 +384,7 @@ snek_code_move(void *addr) code_move(code->code, code->size); } -const snek_mem_t SNEK_MEM_DECLARE(snek_code_mem) = { +CONST snek_mem_t snek_code_mem = { .size = snek_code_size, .mark = snek_code_mark, .move = snek_code_move, @@ -410,7 +410,7 @@ snek_compile_move(void *addr) code_move(addr, snek_compile_size); } -const snek_mem_t SNEK_MEM_DECLARE(snek_compile_mem) = { +CONST snek_mem_t snek_compile_mem = { .size = _snek_compile_size, .mark = snek_compile_mark, .move = snek_compile_move, @@ -421,7 +421,7 @@ const snek_mem_t SNEK_MEM_DECLARE(snek_compile_mem) = { #define dbg(fmt, args...) fprintf(stderr, fmt, ## args) -static const char * const snek_op_names[] = { +static CONST char * CONST snek_op_names[] = { [snek_op_plus] = "plus", [snek_op_minus] = "minus", [snek_op_times] = "times", @@ -557,7 +557,7 @@ snek_code_dump_instruction(snek_code_t *code, snek_offset_t ip) memcpy(&id, &code->code[ip], sizeof(snek_id_t)); dbg("(%5d) ", id); if (id) { - const char *name = snek_name_string(id); + CONST char *name = snek_name_string(id); if (!name) dbg("\n", id); else diff --git a/snek-error.c b/snek-error.c index 0edc61e8..db5a136b 100644 --- a/snek-error.c +++ b/snek-error.c @@ -16,10 +16,6 @@ bool snek_abort; -#ifndef ERROR_FETCH_FORMAT_CHAR -#define ERROR_FETCH_FORMAT_CHAR(a) (*(a)) -#endif - static void puts_clean(char *s) { @@ -41,7 +37,7 @@ puts_clean(char *s) } snek_poly_t -snek_error_name(const char *format, ...) +snek_error_name(CONST char *format, ...) { va_list args; char c; @@ -55,9 +51,9 @@ snek_error_name(const char *format, ...) #else fprintf(stderr, "%s:%d ", snek_file, snek_line); #endif - while ((c = ERROR_FETCH_FORMAT_CHAR(format++))) { + while ((c = *format++)) { if (c == '%') { - switch ((c = ERROR_FETCH_FORMAT_CHAR(format++))) { + switch ((c = *format++)) { case 'd': fprintf(stderr, "%d", va_arg(args, int)); break; @@ -82,7 +78,7 @@ snek_error_name(const char *format, ...) } snek_poly_t -snek_error_0_name(const char *string) +snek_error_0_name(CONST char *string) { return snek_error_name(string); } diff --git a/snek-exec.c b/snek-exec.c index 0886e158..c7fae318 100644 --- a/snek-exec.c +++ b/snek-exec.c @@ -669,14 +669,14 @@ snek_assign(snek_id_t id, snek_op_t op) * Call a builtin function */ static void -snek_call_builtin(const snek_builtin_t *builtin, uint8_t nposition, uint8_t nnamed) +snek_call_builtin(CONST snek_builtin_t *builtin, uint8_t nposition, uint8_t nnamed) { snek_poly_t *actuals = &snek_stack[snek_stackp - (nposition + (nnamed << 1))]; - snek_soffset_t nformal = SNEK_BUILTIN_NFORMAL(builtin); + snek_soffset_t nformal = builtin->nformal; /* Varargs functions have nformal == -1 */ if (nformal < 0) { - snek_a = SNEK_BUILTIN_FUNCV(builtin)(nposition, nnamed, actuals); + snek_a = (builtin->funcv)(nposition, nnamed, actuals); } else if (nposition != nformal || nnamed) { /* Otherwise, complain if the argument count doesn't @@ -687,19 +687,19 @@ snek_call_builtin(const snek_builtin_t *builtin, uint8_t nposition, uint8_t nnam } else { switch (nformal) { case 0: - snek_a = SNEK_BUILTIN_FUNC0(builtin)(); + snek_a = builtin->func0(); break; case 1: - snek_a = SNEK_BUILTIN_FUNC1(builtin)(actuals[0]); + snek_a = builtin->func1(actuals[0]); break; #if SNEK_BUILTIN_NAMES_MAX_ARGS >= 2 case 2: - snek_a = SNEK_BUILTIN_FUNC2(builtin)(actuals[0], actuals[1]); + snek_a = builtin->func2(actuals[0], actuals[1]); break; #endif #if SNEK_BUILTIN_NAMES_MAX_ARGS >= 3 case 3: - snek_a = SNEK_BUILTIN_FUNC3(builtin)(actuals[0], actuals[1], actuals[2]); + snek_a = builtin->func3(actuals[0], actuals[1], actuals[2]); break; #endif #if SNEK_BUILTIN_NAMES_MAX_ARGS >= 4 diff --git a/snek-frame.c b/snek-frame.c index cf45c9e2..0e7727e9 100644 --- a/snek-frame.c +++ b/snek-frame.c @@ -253,7 +253,7 @@ snek_frame_move(void *addr) } } -const snek_mem_t SNEK_MEM_DECLARE(snek_frame_mem) = { +CONST snek_mem_t snek_frame_mem = { .size = snek_frame_size, .mark = snek_frame_mark, .move = snek_frame_move, diff --git a/snek-gram.ll b/snek-gram.ll index 6e3c2370..5083e4f3 100644 --- a/snek-gram.ll +++ b/snek-gram.ll @@ -87,10 +87,7 @@ stat : simple-stat compound-stat | NL ; -simple-stat : @{ snek_code_add_line(); }@ small-stat small-stats-p nl-or-end - ; -nl-or-end : NL - | END +simple-stat : @{ snek_code_add_line(); }@ small-stat small-stats-p NL ; small-stats-p : SEMI small-stat small-stats-p | diff --git a/snek-install.defs b/snek-install.defs index 0e4aa24e..96282d6b 100644 --- a/snek-install.defs +++ b/snek-install.defs @@ -28,7 +28,6 @@ endif FIRMWARE ?= \ $(SNEK_PORTS)/crickit/snek-crickit-$(SNEK_VERSION).uf2 \ $(SNEK_PORTS)/duemilanove/snek-duemilanove-$(SNEK_VERSION).hex \ - $(SNEK_PORTS)/duemilanove-big/snek-duemilanove-big-$(SNEK_VERSION).hex \ $(SNEK_PORTS)/ev3/snek-ev3-$(SNEK_VERSION) \ $(SNEK_PORTS)/feather/snek-feather-$(SNEK_VERSION).uf2 \ $(SNEK_PORTS)/grove/snek-grove-$(SNEK_VERSION).hex \ @@ -36,7 +35,6 @@ FIRMWARE ?= \ $(SNEK_PORTS)/itsybitsy5v/snek-itsybitsy5v-$(SNEK_VERSION).hex \ $(SNEK_PORTS)/itsybitsym0/snek-itsybitsym0-$(SNEK_VERSION).uf2 \ $(SNEK_PORTS)/lilypad/snek-lilypad-$(SNEK_VERSION).hex \ - $(SNEK_PORTS)/lilypad-big/snek-lilypad-big-$(SNEK_VERSION).hex \ $(SNEK_PORTS)/mega/snek-mega-$(SNEK_VERSION).hex \ $(SNEK_PORTS)/metrom0/snek-metrom0-$(SNEK_VERSION).uf2 \ $(SNEK_PORTS)/nano33iot/snek-nano33iot-$(SNEK_VERSION).uf2 \ @@ -47,7 +45,6 @@ FIRMWARE ?= \ $(SNEK_PORTS)/snekboard/snek-board-$(SNEK_VERSION).uf2 \ $(SNEK_PORTS)/uduino/snek-uduino-$(SNEK_VERSION).hex \ $(SNEK_PORTS)/uno/snek-uno-$(SNEK_VERSION).hex \ - $(SNEK_PORTS)/uno-big/snek-uno-big-$(SNEK_VERSION).hex \ $(SNEK_PORTS)/xiao/snek-xiao-$(SNEK_VERSION).uf2 \ $(SNEK_PORTS_HIFIVE1REVB) $(SNEK_PORTS_ESP32) \ $(SNEK_PORTS_NANO_EVERY) diff --git a/snek-lex.c b/snek-lex.c index f0f7cbc3..b9da988c 100644 --- a/snek-lex.c +++ b/snek-lex.c @@ -168,7 +168,7 @@ comment(void) { char c; - while ((c = lexchar() != '\n')) + while ((c = lexchar() != '\n') && !snek_abort) if (c == SNEK_EOF) return false; return true; @@ -323,11 +323,15 @@ string(char q) } } +#ifndef trailing_name +#define trailing_name trailing +#endif + static token_t -trailing(const char *next, snek_op_t without_op, token_t without, snek_op_t with_op, token_t with) +trailing_name(CONST char *next, snek_op_t without_op, token_t without, snek_op_t with_op, token_t with) { char c; - const char *n = next; + CONST char *n = next; bool space = false; /* skip spaces between words */ diff --git a/ports/mega/snek-mega-math.builtin b/snek-math-small.builtin similarity index 88% rename from ports/mega/snek-mega-math.builtin rename to snek-math-small.builtin index 2fa0067f..045bc3f9 100644 --- a/ports/mega/snek-mega-math.builtin +++ b/snek-math-small.builtin @@ -32,15 +32,21 @@ math.isinf, 1 math.isnan, 1 math.ldexp, 2 math.modf, 1 +math.remainder, 2 math.trunc, 1 round, 1 # # Power and logarithmic functions # math.exp, 1 +math.expm1, 1 +math.exp2, 1 math.log, 1 +math.log1p, 1 +math.log2, 1 math.log10, 1 math.pow, 2 +pow, 2, =math.pow # # Trigonometric functions # @@ -58,12 +64,6 @@ math.tan, 1 math.degrees, 1 math.radians, 1 # -# Hyperbolic functions -# -math.cosh, 1 -math.sinh, 1 -math.tanh, 1 -# # Special functions # # @@ -72,5 +72,5 @@ math.tanh, 1 math.pi, -2, 3.141592653589793 math.e, -2, 2.718281828459045 math.tau, -2, 6.283185307179586 -math.inf, -2, INFINITY -math.nan, -2, NAN +math.inf, -2, (snek_poly_t)(float)INFINITY +math.nan, -2, (snek_poly_t)(float)NAN diff --git a/snek-math.c b/snek-math.c index 47c5afa5..9352ec33 100644 --- a/snek-math.c +++ b/snek-math.c @@ -244,17 +244,37 @@ radiansf(float x) { return x * (float) M_PI / 180.0f; } m1(math_degrees, degreesf) m1(math_radians, radiansf) +#ifdef SNEK_BUILTIN_math_acosh m1(math_acosh, acoshf); +#endif +#ifdef SNEK_BUILTIN_math_asinh m1(math_asinh, asinhf); +#endif +#ifdef SNEK_BUILTIN_math_atanh m1(math_atanh, atanhf); +#endif +#ifdef SNEK_BUILTIN_math_cosh m1(math_cosh, coshf); +#endif +#ifdef SNEK_BUILTIN_math_sinh m1(math_sinh, sinhf); +#endif +#ifdef SNEK_BUILTIN_math_tanh m1(math_tanh, tanhf); +#endif +#ifdef SNEK_BUILTIN_math_erf m1(math_erf, erff); +#endif +#ifdef SNEK_BUILTIN_math_erfc m1(math_erfc, erfcf); +#endif + +#ifdef SNEK_BUILTIN_math_gamma m1(math_gamma, tgammaf); +#endif +#ifdef SNEK_BUILTIN_math_lgamma #if defined(WIN32) || defined(__APPLE__) || defined(_PICOLIBC__) m1(math_lgamma, lgammaf); #else @@ -267,3 +287,4 @@ _lgammaf(float f) m1(math_lgamma, _lgammaf); #endif +#endif diff --git a/snek-memory.c b/snek-memory.c index 834eb94e..aeaccde0 100644 --- a/snek-memory.c +++ b/snek-memory.c @@ -23,17 +23,11 @@ uint8_t snek_pool[SNEK_POOL] __attribute__((aligned(SNEK_ALLOC_ROUND))); #endif struct snek_root { - const snek_mem_t *type; + CONST snek_mem_t *type; void **addr; }; -#ifndef SNEK_ROOT_DECLARE -#define SNEK_ROOT_DECLARE(n) n -#define SNEK_ROOT_TYPE(n) ((n)->type) -#define SNEK_ROOT_ADDR(n) ((n)->addr) -#endif - -static const struct snek_root SNEK_ROOT_DECLARE(snek_root)[] = { +static CONST struct snek_root snek_root[] = { { .type = &snek_name_mem, .addr = (void **) (void *) &snek_names, @@ -59,7 +53,7 @@ static const struct snek_root SNEK_ROOT_DECLARE(snek_root)[] = { .addr = (void **) (void *) &snek_empty_tuple, }, { - .type = NULL, + .type = (CONST void *) 0, .addr = (void **) (void *) &snek_a, }, { @@ -194,9 +188,9 @@ snek_size_round(snek_offset_t size) } static snek_offset_t -snek_size(const snek_mem_t *mem, void *addr) +snek_size(CONST snek_mem_t *mem, void *addr) { - return snek_size_round(SNEK_MEM_SIZE(mem)(addr)); + return snek_size_round(mem->size(addr)); } static void @@ -289,7 +283,7 @@ reset_chunks(void) */ static void -walk(bool (*visit_addr)(const struct snek_mem *type, void **addr), +walk(bool (*visit_addr)(CONST struct snek_mem *type, void **addr), bool (*visit_poly)(snek_poly_t *p)) { snek_offset_t i; @@ -298,17 +292,15 @@ walk(bool (*visit_addr)(const struct snek_mem *type, void **addr), for (i = 0; i < snek_stackp; i++) visit_poly(&snek_stack[i]); for (i = 0; i < (snek_offset_t) SNEK_ROOT; i++) { - const snek_mem_t *mem = SNEK_ROOT_TYPE(&snek_root[i]); - if (mem) { - void **a = SNEK_ROOT_ADDR(&snek_root[i]), *v; - if (a == NULL || (v = *a) != NULL) { - visit_addr(mem, a); - } + CONST snek_mem_t *type = snek_root[i].type; + void **addr = snek_root[i].addr; + if (type) { + if (addr == NULL || *addr != NULL) + visit_addr(type, addr); } else { - snek_poly_t *a = (snek_poly_t *) SNEK_ROOT_ADDR(&snek_root[i]), p; - if (a && !snek_is_null(p = *a)) { - visit_poly(a); - } + snek_poly_t *p = (snek_poly_t *) addr; + if (!snek_is_null(*p)) + visit_poly(p); } } while (!snek_offset_is_none(snek_note_list)) { @@ -329,7 +321,7 @@ walk(bool (*visit_addr)(const struct snek_mem *type, void **addr), } static bool -snek_mark_ref(const struct snek_mem *type, void **ref) +snek_mark_ref(CONST struct snek_mem *type, void **ref) { return snek_mark_addr(type, *ref); } @@ -426,11 +418,11 @@ snek_collect(uint8_t style) for (; c < chunk_last; c++) { snek_offset_t size = snek_chunk[c].size; + snek_chunk[c].new_offset = top; + debug_memory(" moving %d -> %d (%d)\n", snek_chunk[c].old_offset, top, size); - snek_chunk[c].new_offset = top; - memmove(&snek_pool[top], &snek_pool[snek_chunk[c].old_offset], size); @@ -494,7 +486,7 @@ snek_mark_blob(void *addr, snek_offset_t size) #ifdef DEBUG_MEMORY static const char * -type_name(const struct snek_mem *type) +type_name(CONST struct snek_mem *type) { if (type == &snek_code_mem) return "code"; @@ -520,7 +512,7 @@ type_name(const struct snek_mem *type) #endif bool -snek_mark_block_addr(const struct snek_mem *type, void *addr) +snek_mark_block_addr(CONST struct snek_mem *type, void *addr) { bool ret; ret = snek_mark_blob(addr, snek_size(type, addr)); @@ -534,24 +526,24 @@ snek_mark_block_addr(const struct snek_mem *type, void *addr) * Mark an object and all that it refereces */ bool -snek_mark_addr(const struct snek_mem *type, void *addr) +snek_mark_addr(CONST struct snek_mem *type, void *addr) { bool ret; ret = snek_mark_block_addr(type, addr); if (!ret) - SNEK_MEM_MARK(type)(addr); + type->mark(addr); return ret; } bool -snek_mark_offset(const struct snek_mem *type, snek_offset_t offset) +snek_mark_offset(CONST struct snek_mem *type, snek_offset_t offset) { if (snek_offset_is_none(offset)) return true; return snek_mark_addr(type, pool_addr(offset)); } -const struct snek_mem SNEK_MEMS_DECLARE(_snek_mems)[] = { +CONST struct snek_mem _snek_mems[] = { [snek_list-1] = { .size = snek_list_size, .mark = snek_list_mark, @@ -647,7 +639,7 @@ snek_move_block_offset(void *ref) return false; } -bool +static bool snek_move_block_addr(void **ref) { void *addr = *ref; @@ -667,23 +659,23 @@ snek_move_block_addr(void **ref) } bool -snek_move_addr(const struct snek_mem *type, void **ref) +snek_move_addr(CONST struct snek_mem *type, void **ref) { bool ret; ret = snek_move_block_addr(ref); if (!ret) - SNEK_MEM_MOVE(type)(*ref); + type->move(*ref); return ret; } bool -snek_move_offset(const struct snek_mem *type, snek_offset_t *ref) +snek_move_offset(CONST struct snek_mem *type, snek_offset_t *ref) { bool ret; ret = snek_move_block_offset(ref); if (!ret) - SNEK_MEM_MOVE(type)(pool_addr(*ref)); + type->move(pool_addr(*ref)); return ret; } diff --git a/snek-name.c b/snek-name.c index e557a1ab..37ee5025 100644 --- a/snek-name.c +++ b/snek-name.c @@ -24,9 +24,6 @@ snek_id_t snek_id = SNEK_BUILTIN_END; #define SNEK_BUILTIN_NAMES(a) (snek_builtin_names[a]) #endif -#ifndef SNEK_BUILTIN_NAMES_CMP -#define SNEK_BUILTIN_NAMES_CMP(a,b) strcmp(a,b) -#endif #ifndef snek_builtin_names_return #define snek_builtin_names_return(a) ((const char *) (a)) #endif @@ -55,9 +52,9 @@ snek_name_id_builtin(char *name, bool *keyword) for (i = 0; i < sizeof (snek_builtin_names); - i += snek_builtin_names_len((const char *) &snek_builtin_names[i+k]) + 1 + k) + i += snek_builtin_names_len(&snek_builtin_names[i+k]) + 1 + k) { - if (SNEK_BUILTIN_NAMES_CMP(name, (const char *) &snek_builtin_names[i+k]) == 0) { + if (snek_const_strcmp(name, &snek_builtin_names[i+k]) == 0) { if (id >= SNEK_BUILTIN_END) { id = SNEK_BUILTIN_ID(i); *keyword = true; @@ -82,7 +79,7 @@ snek_name_string_builtin(snek_id_t id) for (i = 0; --id; - i += snek_builtin_names_len((const char *) &snek_builtin_names[i]) + 1) + i += snek_builtin_names_len(&snek_builtin_names[i]) + 1) ; return snek_builtin_names_return(&snek_builtin_names[i]); } @@ -167,7 +164,7 @@ snek_name_move(void *addr) } } -const snek_mem_t SNEK_MEM_DECLARE(snek_name_mem) = { +CONST snek_mem_t snek_name_mem = { .size = snek_name_size, .mark = snek_name_mark, .move = snek_name_move, diff --git a/snek-pow.c b/snek-pow.c index 1e858f67..59c9e7ea 100644 --- a/snek-pow.c +++ b/snek-pow.c @@ -19,7 +19,7 @@ #include "snek.h" #include -#ifdef __AVR__ +#if defined(__AVR__) && __AVR_LIBC_VERSION__ < 20201UL #define float double #endif @@ -117,7 +117,7 @@ logf(float a) */ static inline float -ipow(float a, uint32_t x) +ipow(float a, uint8_t x) { float r = 1; while (x) { @@ -132,7 +132,7 @@ ipow(float a, uint32_t x) float powf(float a, float b) { - uint32_t u = b; + uint8_t u = b; if (u == b) return ipow(a, u); return expf(logf(a) * b); diff --git a/snek-ssd1315.c b/snek-ssd1315.c index f994299d..2a37a6df 100644 --- a/snek-ssd1315.c +++ b/snek-ssd1315.c @@ -53,7 +53,7 @@ #define SSD_SET_FADE 0x23 /* + 1 byte */ #define SSD_SET_ZOOM 0xd6 /* + 1 byte */ -static const PROGMEM uint8_t setup[] = { +static CONST uint8_t setup[] = { 0x00, SSD_DISPLAY_ON(0), /* display off */ SSD_SET_START_LINE(0), @@ -159,7 +159,7 @@ snek_builtin_draw_erase(void) memset(fb, '\0', sizeof(fb)); for (page = 0; page < 8; page++) { ssd_start_write(0, page); - for (i = 0; i < 1024; i++) + for (i = 0; i < (SCREEN_WIDTH * SCREEN_HEIGHT)>>3; i++) snek_i2c_write(0); snek_i2c_stop(); } @@ -174,7 +174,7 @@ snek_oled_init(void) uint8_t i; ssd_start(0x00); for (i = 0; i < SETUP_LEN; i++) - snek_i2c_write(pgm_read_byte(&setup[i])); + snek_i2c_write(setup[i]); snek_i2c_stop(); snek_builtin_draw_erase(); } diff --git a/snek.defs b/snek.defs index 95a12446..67a45cb8 100644 --- a/snek.defs +++ b/snek.defs @@ -81,6 +81,8 @@ SNEK_MOST_WARNINGS = \ -Wmissing-prototypes \ -Wmissing-declarations \ -Wnested-externs \ + -fstrict-flex-arrays=0 \ + --strict-flex-arrays=3 \ -Wshadow ifeq ($(SNEK_CLANG),yes) diff --git a/snek.h b/snek.h index a4c30df3..575521d1 100644 --- a/snek.h +++ b/snek.h @@ -193,17 +193,6 @@ typedef struct snek_mem { #endif } snek_mem_t; -#ifndef SNEK_MEM_DECLARE -#define SNEK_MEM_DECLARE(n) n -#define SNEK_MEM_SIZE(m) ((m)->size) -#define SNEK_MEM_MARK(m) ((m)->mark) -#define SNEK_MEM_MOVE(m) ((m)->move) -#endif - -#ifndef SNEK_MEMS_DECLARE -#define SNEK_MEMS_DECLARE(n) n -#endif - #ifdef SNEK_MEM_INCLUDE_NAME #define SNEK_MEM_DECLARE_NAME(_name) .name = _name, #else @@ -227,7 +216,7 @@ typedef struct snek_list { typedef struct snek_code { snek_offset_t size; - uint8_t code[0]; + uint8_t code[]; } snek_code_t; typedef struct snek_range { @@ -249,14 +238,14 @@ typedef struct snek_func { uint8_t nformal; uint8_t nrequired; snek_offset_t code; - snek_id_t formals[0]; + snek_id_t formals[]; } snek_func_t; #define SNEK_FUNC_VARARGS SNEK_SOFFSET_NONE typedef struct snek_name { snek_offset_t next; - char name[0]; + char name[]; } snek_name_t; typedef struct snek_variable { @@ -269,7 +258,7 @@ typedef struct snek_frame { snek_offset_t code; snek_offset_t ip; snek_offset_t nvariables; - snek_variable_t variables[0]; + snek_variable_t variables[]; } snek_frame_t; @@ -313,7 +302,15 @@ typedef struct snek_buf { void *closure; } snek_buf_t; -extern const snek_builtin_t snek_builtins[]; +extern CONST snek_builtin_t snek_builtins[]; + +#ifndef snek_const_strcpy +#define snek_const_strcpy(a,b) strcpy(a,b) +#endif + +#ifndef snek_const_strcmp +#define snek_const_strcmp(a,b) strcmp(a,(const char *) (b)) +#endif #define SNEK_BUILTIN_FLOAT -2 #define SNEK_BUILTIN_VARARGS -1 @@ -430,7 +427,7 @@ void snek_code_add_number(float number); void -snek_code_add_string(char *string); +snek_code_add_string(const char *string); void snek_code_add_op_offset(snek_op_t op, snek_offset_t offset); @@ -502,8 +499,8 @@ snek_offset_t snek_code_dump_instruction(snek_code_t *code, snek_offset_t ip); #endif -extern const snek_mem_t snek_code_mem; -extern const snek_mem_t snek_compile_mem; +extern CONST snek_mem_t snek_code_mem; +extern CONST snek_mem_t snek_compile_mem; /* snek-exec.c */ @@ -536,10 +533,10 @@ snek_exec(snek_code_t *code); #endif snek_poly_t -snek_error_name(const char *format, ...); +snek_error_name(CONST char *format, ...); snek_poly_t -snek_error_0_name(const char *string); +snek_error_0_name(CONST char *string); snek_poly_t snek_error_step(void); @@ -603,7 +600,7 @@ snek_id_is_local(snek_id_t id); bool snek_id_del(snek_id_t id); -extern const snek_mem_t snek_frame_mem; +extern CONST snek_mem_t snek_frame_mem; /* snek-func.c */ @@ -721,28 +718,25 @@ bool snek_mark_blob(void *addr, snek_offset_t size); bool -snek_mark_block_addr(const struct snek_mem *type, void *addr); +snek_mark_block_addr(CONST struct snek_mem *type, void *addr); bool -snek_mark_addr(const struct snek_mem *type, void *addr); +snek_mark_addr(CONST struct snek_mem *type, void *addr); bool -snek_mark_offset(const struct snek_mem *type, snek_offset_t offset); +snek_mark_offset(CONST struct snek_mem *type, snek_offset_t offset); bool snek_move_block_offset(void *ref); -bool -snek_move_block_addr(void **ref); - bool snek_poly_move(snek_poly_t *ref); bool -snek_move_addr(const struct snek_mem *type, void **ref); +snek_move_addr(CONST struct snek_mem *type, void **ref); bool -snek_move_offset(const struct snek_mem *type, snek_offset_t *ref); +snek_move_offset(CONST struct snek_mem *type, snek_offset_t *ref); void * snek_alloc(snek_offset_t size); @@ -765,9 +759,9 @@ snek_pool_addr(snek_offset_t offset); snek_offset_t snek_pool_offset(const void *addr); -extern const struct snek_mem SNEK_MEMS_DECLARE(_snek_mems)[]; +extern CONST struct snek_mem _snek_mems[]; -static inline const struct snek_mem *snek_mems(snek_type_t type) +static inline CONST struct snek_mem *snek_mems(snek_type_t type) { /* Oddly, the compiler complains about this particular array * operation. However, this lets us declare _snek_mems with @@ -787,7 +781,7 @@ snek_name_id(char *name, bool *keyword); const char * snek_name_string(snek_id_t id); -extern const snek_mem_t snek_name_mem; +extern CONST snek_mem_t snek_name_mem; extern snek_name_t *snek_names; /* snek-parse.c */ @@ -959,7 +953,7 @@ snek_builtin_id_to_poly(snek_id_t id) { if (id < SNEK_BUILTIN_MAX_FUNC) return snek_offset_to_poly(id << SNEK_ALLOC_SHIFT, snek_builtin); - return SNEK_BUILTIN_VALUE(&snek_builtins[id-1]); + return snek_builtins[id-1].value; } static inline snek_id_t @@ -968,7 +962,7 @@ snek_poly_to_builtin_id(snek_poly_t a) return snek_poly_to_offset(a) >> SNEK_ALLOC_SHIFT; } -static inline const snek_builtin_t * +static inline CONST snek_builtin_t * snek_poly_to_builtin(snek_poly_t a) { return snek_builtins + (snek_poly_to_builtin_id(a) - 1); diff --git a/ubaboot b/ubaboot new file mode 160000 index 00000000..6baf51e8 --- /dev/null +++ b/ubaboot @@ -0,0 +1 @@ +Subproject commit 6baf51e82020c8ddb1fd5425d4d133c2fe39ae56