From 148f6e0a107d9e88509958700351794f2f971312 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 30 Oct 2016 19:06:20 -0700 Subject: altos/stmf0: Add USART support The STM32F0 usart can be operated much like the STM32L usart, but the registers are all moved around. Signed-off-by: Keith Packard --- src/stmf0/ao_arch_funcs.h | 13 +- src/stmf0/ao_serial_stm.c | 500 ++++++++++++++++++++++++++++++++++++++++++++++ src/stmf0/stm32f0.h | 125 ++++++++++++ 3 files changed, 637 insertions(+), 1 deletion(-) create mode 100644 src/stmf0/ao_serial_stm.c (limited to 'src') diff --git a/src/stmf0/ao_arch_funcs.h b/src/stmf0/ao_arch_funcs.h index 8b6234c4..d35bafbd 100644 --- a/src/stmf0/ao_arch_funcs.h +++ b/src/stmf0/ao_arch_funcs.h @@ -314,7 +314,18 @@ struct ao_stm_usart { struct ao_fifo rx_fifo; struct ao_fifo tx_fifo; struct stm_usart *reg; - uint8_t tx_started; + uint8_t tx_running; + uint8_t draining; +#if HAS_SERIAL_SW_FLOW + /* RTS - 0 if we have FIFO space, 1 if not + * CTS - 0 if we can send, 0 if not + */ + struct stm_gpio *gpio_rts; + struct stm_gpio *gpio_cts; + uint8_t pin_rts; + uint8_t pin_cts; + uint8_t rts; +#endif }; #if HAS_SERIAL_1 diff --git a/src/stmf0/ao_serial_stm.c b/src/stmf0/ao_serial_stm.c new file mode 100644 index 00000000..30b0dbd2 --- /dev/null +++ b/src/stmf0/ao_serial_stm.c @@ -0,0 +1,500 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include + +void +ao_debug_out(char c) +{ + if (c == '\n') + ao_debug_out('\r'); + while (!(stm_usart1.isr & (1 << STM_USART_ISR_TXE))); + stm_usart1.tdr = c; +} + +static int +_ao_usart_tx_start(struct ao_stm_usart *usart) +{ + if (!ao_fifo_empty(usart->tx_fifo)) { +#if HAS_SERIAL_SW_FLOW + if (usart->gpio_cts && ao_gpio_get(usart->gpio_cts, usart->pin_cts, foo) == 1) { + ao_exti_enable(usart->gpio_cts, usart->pin_cts); + return 0; + } +#endif + if (usart->reg->isr & (1 << STM_USART_ISR_TXE)) + { + usart->tx_running = 1; + usart->reg->cr1 |= (1 << STM_USART_CR1_TXEIE) | (1 << STM_USART_CR1_TCIE); + ao_fifo_remove(usart->tx_fifo, usart->reg->tdr); + ao_wakeup(&usart->tx_fifo); + return 1; + } + } + return 0; +} + +#if HAS_SERIAL_SW_FLOW +static void +_ao_usart_cts(struct ao_stm_usart *usart) +{ + if (_ao_usart_tx_start(usart)) + ao_exti_disable(usart->gpio_cts, usart->pin_cts); +} +#endif + +static void +_ao_usart_rx(struct ao_stm_usart *usart, int stdin) +{ + if (usart->reg->isr & (1 << STM_USART_ISR_RXNE)) { + usart->reg->icr = (1 << STM_USART_ICR_ORECF); + if (!ao_fifo_full(usart->rx_fifo)) { + ao_fifo_insert(usart->rx_fifo, usart->reg->rdr); + ao_wakeup(&usart->rx_fifo); + if (stdin) + ao_wakeup(&ao_stdin_ready); +#if HAS_SERIAL_SW_FLOW + /* If the fifo is nearly full, turn off RTS and wait + * for it to drain a bunch + */ + if (usart->gpio_rts && ao_fifo_mostly(usart->rx_fifo)) { + ao_gpio_set(usart->gpio_rts, usart->pin_rts, usart->pin_rts, 1); + usart->rts = 0; + } +#endif + } else { + usart->reg->cr1 &= ~(1 << STM_USART_CR1_RXNEIE); + } + } +} + +static void +ao_usart_isr(struct ao_stm_usart *usart, int stdin) +{ + _ao_usart_rx(usart, stdin); + + if (!_ao_usart_tx_start(usart)) + usart->reg->cr1 &= ~(1<< STM_USART_CR1_TXEIE); + + if (usart->reg->isr & (1 << STM_USART_ISR_TC)) { + usart->tx_running = 0; + usart->reg->cr1 &= ~(1 << STM_USART_CR1_TCIE); + if (usart->draining) { + usart->draining = 0; + ao_wakeup(&usart->tx_fifo); + } + } +} + +static int +_ao_usart_pollchar(struct ao_stm_usart *usart) +{ + int c; + + if (ao_fifo_empty(usart->rx_fifo)) + c = AO_READ_AGAIN; + else { + uint8_t u; + ao_fifo_remove(usart->rx_fifo,u); + if ((usart->reg->cr1 & (1 << STM_USART_CR1_RXNEIE)) == 0) { + if (ao_fifo_barely(usart->rx_fifo)) + usart->reg->cr1 |= (1 << STM_USART_CR1_RXNEIE); + } +#if HAS_SERIAL_SW_FLOW + /* If we've cleared RTS, check if there's space now and turn it back on */ + if (usart->gpio_rts && usart->rts == 0 && ao_fifo_barely(usart->rx_fifo)) { + ao_gpio_set(usart->gpio_rts, usart->pin_rts, foo, 0); + usart->rts = 1; + } +#endif + c = u; + } + return c; +} + +static char +ao_usart_getchar(struct ao_stm_usart *usart) +{ + int c; + ao_arch_block_interrupts(); + while ((c = _ao_usart_pollchar(usart)) == AO_READ_AGAIN) + ao_sleep(&usart->rx_fifo); + ao_arch_release_interrupts(); + return (char) c; +} + +static inline uint8_t +_ao_usart_sleep_for(struct ao_stm_usart *usart, uint16_t timeout) +{ + return ao_sleep_for(&usart->rx_fifo, timeout); +} + +static void +ao_usart_putchar(struct ao_stm_usart *usart, char c) +{ + ao_arch_block_interrupts(); + while (ao_fifo_full(usart->tx_fifo)) + ao_sleep(&usart->tx_fifo); + ao_fifo_insert(usart->tx_fifo, c); + _ao_usart_tx_start(usart); + ao_arch_release_interrupts(); +} + +static void +ao_usart_drain(struct ao_stm_usart *usart) +{ + ao_arch_block_interrupts(); + while (!ao_fifo_empty(usart->tx_fifo) || usart->tx_running) { + usart->draining = 1; + ao_sleep(&usart->tx_fifo); + } + ao_arch_release_interrupts(); +} + +static const struct { + uint32_t brr; +} ao_usart_speeds[] = { + [AO_SERIAL_SPEED_4800] = { + AO_PCLK / 4800 + }, + [AO_SERIAL_SPEED_9600] = { + AO_PCLK / 9600 + }, + [AO_SERIAL_SPEED_19200] = { + AO_PCLK / 19200 + }, + [AO_SERIAL_SPEED_57600] = { + AO_PCLK / 57600 + }, + [AO_SERIAL_SPEED_115200] = { + AO_PCLK / 115200 + }, +}; + +static void +ao_usart_set_speed(struct ao_stm_usart *usart, uint8_t speed) +{ + if (speed > AO_SERIAL_SPEED_115200) + return; + usart->reg->brr = ao_usart_speeds[speed].brr; +} + +static void +ao_usart_init(struct ao_stm_usart *usart) +{ + usart->reg->cr1 = ((0 << STM_USART_CR1_M1) | + (0 << STM_USART_CR1_EOBIE) | + (0 << STM_USART_CR1_RTOIE) | + (0 << STM_USART_CR1_DEAT) | + (0 << STM_USART_CR1_DEDT) | + (0 << STM_USART_CR1_OVER8) | + (0 << STM_USART_CR1_CMIE) | + (0 << STM_USART_CR1_MME) | + (0 << STM_USART_CR1_M0) | + (0 << STM_USART_CR1_WAKE) | + (0 << STM_USART_CR1_PCE) | + (0 << STM_USART_CR1_PS) | + (0 << STM_USART_CR1_PEIE) | + (0 << STM_USART_CR1_TXEIE) | + (0 << STM_USART_CR1_TCIE) | + (1 << STM_USART_CR1_RXNEIE) | + (0 << STM_USART_CR1_IDLEIE) | + (1 << STM_USART_CR1_TE) | + (1 << STM_USART_CR1_RE) | + (0 << STM_USART_CR1_UESM) | + (0 << STM_USART_CR1_UE)); + + usart->reg->cr2 = ((0 << STM_USART_CR2_ADD) | + (0 << STM_USART_CR2_RTOEN) | + (0 << STM_USART_CR2_ABRMOD) | + (0 << STM_USART_CR2_ABREN) | + (0 << STM_USART_CR2_MSBFIRST) | + (0 << STM_USART_CR2_DATAINV) | + (0 << STM_USART_CR2_TXINV) | + (0 << STM_USART_CR2_RXINV) | + (0 << STM_USART_CR2_SWAP) | + (0 << STM_USART_CR2_LINEN) | + (0 << STM_USART_CR2_STOP) | + (0 << STM_USART_CR2_CLKEN) | + (0 << STM_USART_CR2_CPOL) | + (0 << STM_USART_CR2_CHPA) | + (0 << STM_USART_CR2_LBCL) | + (0 << STM_USART_CR2_LBDIE) | + (0 << STM_USART_CR2_LBDL) | + (0 << STM_USART_CR2_ADDM7)); + + usart->reg->cr3 = ((0 << STM_USART_CR3_WUFIE) | + (0 << STM_USART_CR3_WUS) | + (0 << STM_USART_CR3_SCARCNT) | + (0 << STM_USART_CR3_DEP) | + (0 << STM_USART_CR3_DEM) | + (0 << STM_USART_CR3_DDRE) | + (0 << STM_USART_CR3_OVRDIS) | + (0 << STM_USART_CR3_ONEBIT) | + (0 << STM_USART_CR3_CTIIE) | + (0 << STM_USART_CR3_CTSE) | + (0 << STM_USART_CR3_RTSE) | + (0 << STM_USART_CR3_DMAT) | + (0 << STM_USART_CR3_DMAR) | + (0 << STM_USART_CR3_SCEN) | + (0 << STM_USART_CR3_NACK) | + (0 << STM_USART_CR3_HDSEL) | + (0 << STM_USART_CR3_IRLP) | + (0 << STM_USART_CR3_IREN) | + (0 << STM_USART_CR3_EIE)); + + + /* Pick a 9600 baud rate */ + ao_usart_set_speed(usart, AO_SERIAL_SPEED_9600); + + /* Enable the usart */ + usart->reg->cr1 |= (1 << STM_USART_CR1_UE); + +} + +#if HAS_SERIAL_HW_FLOW +static void +ao_usart_set_flow(struct ao_stm_usart *usart) +{ + usart->reg->cr3 |= ((1 << STM_USART_CR3_CTSE) | + (1 << STM_USART_CR3_RTSE)); +} +#endif + +#if HAS_SERIAL_1 + +struct ao_stm_usart ao_stm_usart1; + +void stm_usart1_isr(void) { ao_usart_isr(&ao_stm_usart1, USE_SERIAL_1_STDIN); } + +char +ao_serial1_getchar(void) +{ + return ao_usart_getchar(&ao_stm_usart1); +} + +void +ao_serial1_putchar(char c) +{ + ao_usart_putchar(&ao_stm_usart1, c); +} + +int +_ao_serial1_pollchar(void) +{ + return _ao_usart_pollchar(&ao_stm_usart1); +} + +uint8_t +_ao_serial1_sleep_for(uint16_t timeout) +{ + return _ao_usart_sleep_for(&ao_stm_usart1, timeout); +} + +void +ao_serial1_drain(void) +{ + ao_usart_drain(&ao_stm_usart1); +} + +void +ao_serial1_set_speed(uint8_t speed) +{ + ao_usart_drain(&ao_stm_usart1); + ao_usart_set_speed(&ao_stm_usart1, speed); +} +#endif /* HAS_SERIAL_1 */ + +#if HAS_SERIAL_2 + +struct ao_stm_usart ao_stm_usart2; + +void stm_usart2_isr(void) { ao_usart_isr(&ao_stm_usart2, USE_SERIAL_2_STDIN); } + +char +ao_serial2_getchar(void) +{ + return ao_usart_getchar(&ao_stm_usart2); +} + +void +ao_serial2_putchar(char c) +{ + ao_usart_putchar(&ao_stm_usart2, c); +} + +int +_ao_serial2_pollchar(void) +{ + return _ao_usart_pollchar(&ao_stm_usart2); +} + +uint8_t +_ao_serial2_sleep_for(uint16_t timeout) +{ + return _ao_usart_sleep_for(&ao_stm_usart2, timeout); +} + +void +ao_serial2_drain(void) +{ + ao_usart_drain(&ao_stm_usart2); +} + +void +ao_serial2_set_speed(uint8_t speed) +{ + ao_usart_drain(&ao_stm_usart2); + ao_usart_set_speed(&ao_stm_usart2, speed); +} + +#if HAS_SERIAL_SW_FLOW +void +ao_serial2_cts(void) +{ + _ao_usart_cts(&ao_stm_usart2); +} +#endif + +#endif /* HAS_SERIAL_2 */ + +#if HAS_SERIAL_SW_FLOW +static void +ao_serial_set_sw_rts_cts(struct ao_stm_usart *usart, + void (*isr)(void), + struct stm_gpio *port_rts, + int pin_rts, + struct stm_gpio *port_cts, + int pin_cts) +{ + /* Pull RTS low to note that there's space in the FIFO + */ + ao_enable_output(port_rts, pin_rts, foo, 0); + usart->gpio_rts = port_rts; + usart->pin_rts = pin_rts; + usart->rts = 1; + + ao_exti_setup(port_cts, pin_cts, AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED, isr); + usart->gpio_cts = port_cts; + usart->pin_cts = pin_cts; +} +#endif + +void +ao_serial_init(void) +{ +#if HAS_SERIAL_1 + /* + * TX RX + * PA9 PA10 + * PB6 PB7 + */ + +#if SERIAL_1_PA9_PA10 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN); + + stm_afr_set(&stm_gpioa, 9, STM_AFR_AF1); + stm_afr_set(&stm_gpioa, 10, STM_AFR_AF1); +#else +#if SERIAL_1_PB6_PB7 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN); + + stm_afr_set(&stm_gpiob, 6, STM_AFR_AF0); + stm_afr_set(&stm_gpiob, 7, STM_AFR_AF0); +#else +#error "No SERIAL_1 port configuration specified" +#endif +#endif + /* Enable USART */ + stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_USART1EN); + + ao_stm_usart1.reg = &stm_usart1; + ao_usart_init(&ao_stm_usart1); + + stm_nvic_set_enable(STM_ISR_USART1_POS); + stm_nvic_set_priority(STM_ISR_USART1_POS, 4); +#if USE_SERIAL_1_STDIN && !DELAY_SERIAL_1_STDIN + ao_add_stdio(_ao_serial1_pollchar, + ao_serial1_putchar, + NULL); +#endif +#endif + +#if HAS_SERIAL_2 + /* + * TX RX + * PA2 PA3 + * PA14 PA15 + */ + +# if SERIAL_2_PA2_PA3 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN); + + stm_afr_set(&stm_gpioa, 2, STM_AFR_AF1); + stm_afr_set(&stm_gpioa, 3, STM_AFR_AF1); +# if USE_SERIAL_2_FLOW +# if USE_SERIAL_2_SW_FLOW + ao_serial_set_sw_rts_cts(&ao_stm_usart2, + ao_serial2_cts, + SERIAL_2_PORT_RTS, + SERIAL_2_PIN_RTS, + SERIAL_2_PORT_CTS, + SERIAL_2_PIN_CTS); +# else + stm_afr_set(&stm_gpioa, 0, STM_AFR_AF1); + stm_afr_set(&stm_gpioa, 1, STM_AFR_AF1); +# endif +# endif +# else +# if SERIAL_2_PA14_PA15 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN); + + stm_afr_set(&stm_gpioa, 14, STM_AFR_AF1); + stm_afr_set(&stm_gpioa, 15, STM_AFR_AF1); +# if USE_SERIAL_2_FLOW +# error "Don't know how to set flowcontrol for serial 2 on PA14" +# endif +# else +# if SERIAL_2_PA2_PA15 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN); + + stm_afr_set(&stm_gpioa, 2, STM_AFR_AF1); + stm_afr_set(&stm_gpioa, 15, STM_AFR_AF1); +# if USE_SERIAL_2_FLOW +# error "Don't know how to set flowcontrol for serial 2 on PA2_PA15" +# endif +# else +# error "No SERIAL_2 port configuration specified" +# endif +# endif +# endif + /* Enable USART */ + stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_USART2EN); + + ao_stm_usart2.reg = &stm_usart2; + ao_usart_init(&ao_stm_usart2); +# if USE_SERIAL_2_FLOW && !USE_SERIAL_2_SW_FLOW + ao_usart_set_flow(&ao_stm_usart2); +# endif + + stm_nvic_set_enable(STM_ISR_USART2_POS); + stm_nvic_set_priority(STM_ISR_USART2_POS, 4); +# if USE_SERIAL_2_STDIN && !DELAY_SERIAL_2_STDIN + ao_add_stdio(_ao_serial2_pollchar, + ao_serial2_putchar, + NULL); +# endif +#endif +} diff --git a/src/stmf0/stm32f0.h b/src/stmf0/stm32f0.h index 054200e0..182cd963 100644 --- a/src/stmf0/stm32f0.h +++ b/src/stmf0/stm32f0.h @@ -2010,4 +2010,129 @@ struct stm_exti { extern struct stm_exti stm_exti; +struct stm_usart { + vuint32_t cr1; /* control register 1 */ + vuint32_t cr2; /* control register 2 */ + vuint32_t cr3; /* control register 3 */ + vuint32_t brr; /* baud rate register */ + + vuint32_t gtpr; /* guard time and prescaler */ + vuint32_t rtor; /* receiver timeout register */ + vuint32_t rqr; /* request register */ + vuint32_t isr; /* interrupt and status register */ + + vuint32_t icr; /* interrupt flag clear register */ + vuint32_t rdr; /* receive data register */ + vuint32_t tdr; /* transmit data register */ +}; + +#define STM_USART_CR1_M1 28 +#define STM_USART_CR1_EOBIE 27 +#define STM_USART_CR1_RTOIE 26 +#define STM_USART_CR1_DEAT 21 +#define STM_USART_CR1_DEDT 16 +#define STM_USART_CR1_OVER8 15 +#define STM_USART_CR1_CMIE 14 +#define STM_USART_CR1_MME 13 +#define STM_USART_CR1_M0 12 +#define STM_USART_CR1_WAKE 11 +#define STM_USART_CR1_PCE 10 +#define STM_USART_CR1_PS 9 +#define STM_USART_CR1_PEIE 8 +#define STM_USART_CR1_TXEIE 7 +#define STM_USART_CR1_TCIE 6 +#define STM_USART_CR1_RXNEIE 5 +#define STM_USART_CR1_IDLEIE 4 +#define STM_USART_CR1_TE 3 +#define STM_USART_CR1_RE 2 +#define STM_USART_CR1_UESM 1 +#define STM_USART_CR1_UE 0 + +#define STM_USART_CR2_ADD 24 +#define STM_USART_CR2_RTOEN 23 +#define STM_USART_CR2_ABRMOD 21 +#define STM_USART_CR2_ABREN 20 +#define STM_USART_CR2_MSBFIRST 19 +#define STM_USART_CR2_DATAINV 18 +#define STM_USART_CR2_TXINV 17 +#define STM_USART_CR2_RXINV 16 +#define STM_USART_CR2_SWAP 15 +#define STM_USART_CR2_LINEN 14 +#define STM_USART_CR2_STOP 12 +#define STM_USART_CR2_CLKEN 11 +#define STM_USART_CR2_CPOL 10 +#define STM_USART_CR2_CHPA 9 +#define STM_USART_CR2_LBCL 8 +#define STM_USART_CR2_LBDIE 6 +#define STM_USART_CR2_LBDL 5 +#define STM_USART_CR2_ADDM7 4 + +#define STM_USART_CR3_WUFIE 22 +#define STM_USART_CR3_WUS 20 +#define STM_USART_CR3_SCARCNT 17 +#define STM_USART_CR3_DEP 15 +#define STM_USART_CR3_DEM 14 +#define STM_USART_CR3_DDRE 13 +#define STM_USART_CR3_OVRDIS 12 +#define STM_USART_CR3_ONEBIT 11 +#define STM_USART_CR3_CTIIE 10 +#define STM_USART_CR3_CTSE 9 +#define STM_USART_CR3_RTSE 8 +#define STM_USART_CR3_DMAT 7 +#define STM_USART_CR3_DMAR 6 +#define STM_USART_CR3_SCEN 5 +#define STM_USART_CR3_NACK 4 +#define STM_USART_CR3_HDSEL 3 +#define STM_USART_CR3_IRLP 2 +#define STM_USART_CR3_IREN 1 +#define STM_USART_CR3_EIE 0 + +#define STM_USART_GTPR_GT 8 +#define STM_USART_GTPR_PSC 0 + +#define STM_USART_RQR_TXFRQ 4 +#define STM_USART_RQR_RXFRQ 3 +#define STM_USART_RQR_MMRQ 2 +#define STM_USART_RQR_SBKRQ 1 +#define STM_USART_RQR_ABRRQ 0 + +#define STM_USART_ISR_REACK 22 +#define STM_USART_ISR_TEACK 21 +#define STM_USART_ISR_WUF 20 +#define STM_USART_ISR_RWU 19 +#define STM_USART_ISR_SBKF 18 +#define STM_USART_ISR_CMF 17 +#define STM_USART_ISR_BUSY 16 +#define STM_USART_ISR_ABRF 15 +#define STM_USART_ISR_ABRE 14 +#define STM_USART_ISR_EOBF 12 +#define STM_USART_ISR_RTOF 11 +#define STM_USART_ISR_CTS 10 +#define STM_USART_ISR_CTSIF 9 +#define STM_USART_ISR_LBDF 8 +#define STM_USART_ISR_TXE 7 +#define STM_USART_ISR_TC 6 +#define STM_USART_ISR_RXNE 5 +#define STM_USART_ISR_IDLE 4 +#define STM_USART_ISR_ORE 3 +#define STM_USART_ISR_NF 2 +#define STM_USART_ISR_FE 1 +#define STM_USART_ISR_PE 0 + +#define STM_USART_ICR_WUCF 20 +#define STM_USART_ICR_CMCF 17 +#define STM_USART_ICR_EOBCF 12 +#define STM_USART_ICR_RTOCF 11 +#define STM_USART_ICR_CTSCF 9 +#define STM_USART_ICR_LBDCF 8 +#define STM_USART_ICR_TCCF 6 +#define STM_USART_ICR_IDLECF 4 +#define STM_USART_ICR_ORECF 3 +#define STM_USART_ICR_NCF 2 +#define STM_USART_ICR_FECF 1 +#define STM_USART_ICR_PECF 0 + +extern struct stm_usart stm_usart1; +extern struct stm_usart stm_usart2; + #endif /* _STM32F0_H_ */ -- cgit v1.2.3 From e3d8ad6de7d2dfabe45a285b27f465ba68844f05 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 30 Oct 2016 19:08:14 -0700 Subject: altos/nucleo-32: Add basic support for STM32F042 Nucleo-32 board This hooks up the LED, USB and the USART. Signed-off-by: Keith Packard --- src/nucleao-32/Makefile | 71 +++++++++++++++++++++++++++++++++++ src/nucleao-32/ao_nucleo.c | 63 +++++++++++++++++++++++++++++++ src/nucleao-32/ao_pins.h | 56 +++++++++++++++++++++++++++ src/nucleao-32/flash-loader/Makefile | 8 ++++ src/nucleao-32/flash-loader/ao_pins.h | 37 ++++++++++++++++++ 5 files changed, 235 insertions(+) create mode 100644 src/nucleao-32/Makefile create mode 100644 src/nucleao-32/ao_nucleo.c create mode 100644 src/nucleao-32/ao_pins.h create mode 100644 src/nucleao-32/flash-loader/Makefile create mode 100644 src/nucleao-32/flash-loader/ao_pins.h (limited to 'src') diff --git a/src/nucleao-32/Makefile b/src/nucleao-32/Makefile new file mode 100644 index 00000000..a160fd2f --- /dev/null +++ b/src/nucleao-32/Makefile @@ -0,0 +1,71 @@ +# +# AltOS build +# +# + +include ../stmf0/Makefile.defs + +INC = \ + ao.h \ + ao_arch.h \ + ao_arch_funcs.h \ + ao_boot.h \ + ao_pins.h \ + ao_product.h \ + ao_task.h \ + stm32f0.h \ + Makefile + +ALTOS_SRC = \ + ao_boot_chain.c \ + ao_interrupt.c \ + ao_product.c \ + ao_romconfig.c \ + ao_cmd.c \ + ao_config.c \ + ao_task.c \ + ao_led.c \ + ao_dma_stm.c \ + ao_stdio.c \ + ao_panic.c \ + ao_timer.c \ + ao_mutex.c \ + ao_usb_stm.c \ + ao_serial_stm.c \ + ao_exti_stm.c + +PRODUCT=Nucleo-32 +PRODUCT_DEF=-DNUCLEO +IDPRODUCT=0x000a + +CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -Os -g + +PROGNAME=nucleo-32 +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +SRC=$(ALTOS_SRC) ao_nucleo.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) altos.ld + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +$(OBJ): $(INC) + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +load: $(PROG) + stm-load $(PROG) + +distclean: clean + +clean: + rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx + rm -f ao_product.h + +install: + +uninstall: diff --git a/src/nucleao-32/ao_nucleo.c b/src/nucleao-32/ao_nucleo.c new file mode 100644 index 00000000..cda889c6 --- /dev/null +++ b/src/nucleao-32/ao_nucleo.c @@ -0,0 +1,63 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include + +static uint16_t blink_delay, blink_running; + +static void blink(void) { + blink_running = 1; + while (blink_delay) { + ao_led_on(AO_LED_GREEN); + ao_delay(blink_delay); + ao_led_off(AO_LED_GREEN); + ao_delay(blink_delay); + } + blink_running = 0; + ao_wakeup(&blink_running); + ao_exit(); +} + +struct ao_task blink_task; + +static void blink_cmd() { + ao_cmd_decimal(); + blink_delay = ao_cmd_lex_i; + if (blink_delay && !blink_running) + ao_add_task(&blink_task, blink, "blink"); + if (!blink_delay) + while (blink_running) + ao_sleep(&blink_running); +} + +static const struct ao_cmds blink_cmds[] = { + { blink_cmd, "b \0Blink the green LED" }, + { 0, 0 } +}; + +void main(void) +{ + ao_led_init(LEDS_AVAILABLE); + ao_clock_init(); + ao_task_init(); + ao_timer_init(); + ao_dma_init(); + ao_usb_init(); + ao_serial_init(); + ao_cmd_init(); + ao_cmd_register(blink_cmds); + ao_start_scheduler(); +} + + diff --git a/src/nucleao-32/ao_pins.h b/src/nucleao-32/ao_pins.h new file mode 100644 index 00000000..76200176 --- /dev/null +++ b/src/nucleao-32/ao_pins.h @@ -0,0 +1,56 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define LED_PORT_ENABLE STM_RCC_AHBENR_IOPBEN +#define LED_PORT (&stm_gpiob) +#define LED_PIN_GREEN 3 +#define AO_LED_GREEN (1 << LED_PIN_GREEN) +#define AO_LED_PANIC AO_LED_GREEN + +#define LEDS_AVAILABLE (AO_LED_GREEN) + +#define AO_POWER_MANAGEMENT 0 + +/* 48MHz clock based on USB */ +#define AO_HSI48 1 + +/* HCLK = 48MHz */ +#define AO_AHB_PRESCALER 1 +#define AO_RCC_CFGR_HPRE_DIV STM_RCC_CFGR_HPRE_DIV_1 + +/* APB = 48MHz */ +#define AO_APB_PRESCALER 1 +#define AO_RCC_CFGR_PPRE_DIV STM_RCC_CFGR_PPRE_DIV_1 + +#define HAS_USB 1 +#define AO_USB_DIRECTIO 0 +#define AO_PA11_PA12_RMP 0 +#define HAS_BEEP 0 + +#define IS_FLASH_LOADER 0 + +#define HAS_SERIAL_2 1 +#define SERIAL_2_PA2_PA15 1 +#define USE_SERIAL_2_FLOW 0 +#define USE_SERIAL_2_STDIN 1 +#define DELAY_SERIAL_2_STDIN 0 + +#endif /* _AO_PINS_H_ */ diff --git a/src/nucleao-32/flash-loader/Makefile b/src/nucleao-32/flash-loader/Makefile new file mode 100644 index 00000000..2392e998 --- /dev/null +++ b/src/nucleao-32/flash-loader/Makefile @@ -0,0 +1,8 @@ +# +# AltOS flash loader build +# +# + +TOPDIR=../.. +HARDWARE=nucleo-32 +include $(TOPDIR)/stmf0/Makefile-flash.defs diff --git a/src/nucleao-32/flash-loader/ao_pins.h b/src/nucleao-32/flash-loader/ao_pins.h new file mode 100644 index 00000000..8bdbdb1a --- /dev/null +++ b/src/nucleao-32/flash-loader/ao_pins.h @@ -0,0 +1,37 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#include + +/* Pin D3, which is PB0 */ + +#define AO_BOOT_PIN 1 +#define AO_BOOT_APPLICATION_GPIO stm_gpiob +#define AO_BOOT_APPLICATION_PIN 0 +#define AO_BOOT_APPLICATION_VALUE 1 +#define AO_BOOT_APPLICATION_MODE AO_EXTI_MODE_PULL_UP + +/* USB */ +#define HAS_USB 1 +#define AO_USB_DIRECTIO 0 +#define AO_PA11_PA12_RMP 0 + +#endif /* _AO_PINS_H_ */ -- cgit v1.2.3 From 5e24d637a8af09bf64beb7fcf7be4c13eee76a43 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 9 Oct 2016 19:42:42 -0700 Subject: altos/test: Fix tests A couple of fixups for ao_flight_test to dump pyro info only when running in debug mode, and to change the aprs testing Signed-off-by: Keith Packard --- src/kernel/ao_pyro.c | 3 ++- src/test/ao_aprs_test.c | 16 +++++++++++++++- src/test/ao_flight_test.c | 4 ++++ 3 files changed, 21 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/kernel/ao_pyro.c b/src/kernel/ao_pyro.c index c9920ab3..b11d1080 100644 --- a/src/kernel/ao_pyro.c +++ b/src/kernel/ao_pyro.c @@ -75,7 +75,8 @@ uint16_t ao_pyro_fired; #endif #if PYRO_DBG -#define DBG(...) do { printf("\t%d: ", (int) (pyro - ao_config.pyro)); printf(__VA_ARGS__); } while (0) +int pyro_dbg; +#define DBG(...) do { if (pyro_dbg) printf("\t%d: ", (int) (pyro - ao_config.pyro)); printf(__VA_ARGS__); } while (0) #else #define DBG(...) #endif diff --git a/src/test/ao_aprs_test.c b/src/test/ao_aprs_test.c index 3852668a..941bf954 100644 --- a/src/test/ao_aprs_test.c +++ b/src/test/ao_aprs_test.c @@ -60,6 +60,20 @@ ao_aprs_bit(uint8_t bit) void ao_radio_send_aprs(ao_radio_fill_func fill); +static void +aprs_bit_debug(uint8_t tx_bit) +{ + fprintf (stderr, "bit %d\n", tx_bit); +} + +static void +aprs_byte_debug(uint8_t tx_byte) +{ + fprintf(stderr, "byte %02x\n", tx_byte); +} +#define APRS_BIT_DEBUG(x) aprs_bit_debug(x) +#define APRS_BYTE_DEBUG(y) aprs_byte_debug(y) + #include /* @@ -103,7 +117,7 @@ audio_gap(int secs) // This is where we go after reset. int main(int argc, char **argv) { - audio_gap(1); +// audio_gap(1); ao_gps_data.latitude = (45.0 + 28.25 / 60.0) * 10000000; ao_gps_data.longitude = (-(122 + 44.2649 / 60.0)) * 10000000; diff --git a/src/test/ao_flight_test.c b/src/test/ao_flight_test.c index bd7f2ff8..25ddb48f 100644 --- a/src/test/ao_flight_test.c +++ b/src/test/ao_flight_test.c @@ -58,6 +58,7 @@ int ao_gps_new; #define HAS_HMC5883 1 #define HAS_BEEP 1 #define AO_CONFIG_MAX_SIZE 1024 +#define AO_MMA655X_INVERT 0 struct ao_adc { int16_t sense[AO_ADC_NUM_SENSE]; @@ -71,6 +72,7 @@ struct ao_adc { #define AO_ADC_NUM_SENSE 2 #define HAS_MS5607 1 #define HAS_MMA655X 1 +#define AO_MMA655X_INVERT 1 #define HAS_BEEP 1 #define AO_CONFIG_MAX_SIZE 1024 @@ -373,6 +375,8 @@ uint16_t prev_tick; #define AO_PYRO_2 2 #define AO_PYRO_3 3 +#define PYRO_DBG 1 + static void ao_pyro_pin_set(uint8_t pin, uint8_t value) { -- cgit v1.2.3 From f650211f9e99e1d3d0ae13ae559dd1c082f71545 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 12 Dec 2016 16:44:47 -0800 Subject: altos/stm: Make ao_usb_set_address static. Saves a bunch of text space I'm sure this makes the function end up in-lined, which saves enough text space to fit the flash loader in ROM again. Signed-off-by: Keith Packard --- src/stm/ao_usb_stm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/stm/ao_usb_stm.c b/src/stm/ao_usb_stm.c index 0de501ab..f2b8ea94 100644 --- a/src/stm/ao_usb_stm.c +++ b/src/stm/ao_usb_stm.c @@ -174,7 +174,7 @@ static inline uint32_t ao_usb_epr_dtog_tx(uint32_t epr) { * Set current device address and mark the * interface as active */ -void +static void ao_usb_set_address(uint8_t address) { debug("ao_usb_set_address %02x\n", address); -- cgit v1.2.3 From 89ecc32b90565ace078c4a84d4406a4d1f86821a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 17 Dec 2016 20:58:36 -0800 Subject: altos/arm: Align data so that gcc 5.4 doesn't do byte-accesses. Add -Wcast-align Gcc 5.4.1 tracks alignment of data through assignments, so that a uint32_t pointer which comes from byte-aligned uint8_t data: extern uint8_t foo[]; uint32_t *q = (void *) foo; Fetches and stores through this pointer are done bytewise. This is slow (meh), but if q references a device register, things to bad very quickly. This patch works around this bug in the compiler by adding __attribute__((aligned(4))) tags to some variables, or changing them from uint8_t to uint32_t. Places doing this will now be caught as I've added -Wcast-align to the compiler flags. That required adding (void *) casts, after the relevant code was checked to make sure the compiler could tell that the addresses were aligned. Signed-off-by: Keith Packard --- src/aes/ao_aes.c | 9 +++++---- src/drivers/ao_gps_ublox.c | 4 ++-- src/drivers/ao_trng_send.c | 2 +- src/kernel/ao_list.h | 2 +- src/kernel/ao_pyro.c | 4 ++-- src/kernel/ao_task.h | 13 ++++++++++++- src/stm/Makefile.defs | 2 +- src/stm/ao_arch_funcs.h | 9 ++------- src/stm/ao_eeprom_stm.c | 4 ++-- src/stm/ao_usb_stm.c | 2 +- src/stm/stm32l.h | 2 +- src/stmf0/Makefile-stmf0.defs | 2 +- src/stmf0/ao_adc_fast.h | 2 +- src/stmf0/ao_arch_funcs.h | 2 +- src/stmf0/ao_usb_stm.c | 2 +- src/stmf0/stm32f0.h | 2 +- 16 files changed, 35 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/aes/ao_aes.c b/src/aes/ao_aes.c index a04174c6..fd90c5bf 100644 --- a/src/aes/ao_aes.c +++ b/src/aes/ao_aes.c @@ -359,10 +359,10 @@ void xrijndaelDecrypt(word32 block[], roundkey *rkk) #endif uint8_t ao_aes_mutex; -static uint8_t key[16]; +static word32 key[16/4]; static roundkey rkk; -static uint8_t iv[16]; +static word32 iv[16/4]; void ao_aes_set_mode(enum ao_aes_mode mode) @@ -389,10 +389,11 @@ ao_aes_run(__xdata uint8_t *in, __xdata uint8_t *out) { uint8_t i; + uint8_t *_iv = (uint8_t *) iv; for (i = 0; i < 16; i++) - iv[i] ^= in[i]; - xrijndaelEncrypt((word32 *) iv, &rkk); + _iv[i] ^= in[i]; + xrijndaelEncrypt(iv, &rkk); if (out) memcpy(out, iv, 16); } diff --git a/src/drivers/ao_gps_ublox.c b/src/drivers/ao_gps_ublox.c index 22af413a..c720f802 100644 --- a/src/drivers/ao_gps_ublox.c +++ b/src/drivers/ao_gps_ublox.c @@ -156,7 +156,7 @@ static char __xdata *ublox_target; static void ublox_u16(uint8_t offset) { - uint16_t __xdata *ptr = (uint16_t __xdata *) (ublox_target + offset); + uint16_t __xdata *ptr = (uint16_t __xdata *) (void __xdata *) (ublox_target + offset); uint16_t val; val = data_byte(); @@ -175,7 +175,7 @@ static void ublox_u8(uint8_t offset) static void ublox_u32(uint8_t offset) __reentrant { - uint32_t __xdata *ptr = (uint32_t __xdata *) (ublox_target + offset); + uint32_t __xdata *ptr = (uint32_t __xdata *) (void __xdata *) (ublox_target + offset); uint32_t val; val = ((uint32_t) data_byte ()); diff --git a/src/drivers/ao_trng_send.c b/src/drivers/ao_trng_send.c index 85034efd..b1227aaa 100644 --- a/src/drivers/ao_trng_send.c +++ b/src/drivers/ao_trng_send.c @@ -104,7 +104,7 @@ ao_trng_get_cooked(uint16_t *buf) { uint16_t i; uint16_t t; - uint32_t *rnd = (uint32_t *) ao_adc_ring; + uint32_t *rnd = (uint32_t *) (void *) ao_adc_ring; uint8_t mismatch = 0; t = ao_adc_get(AO_USB_IN_SIZE) >> 1; /* one 16-bit value per output byte */ diff --git a/src/kernel/ao_list.h b/src/kernel/ao_list.h index e2df6885..45a3df5b 100644 --- a/src/kernel/ao_list.h +++ b/src/kernel/ao_list.h @@ -138,7 +138,7 @@ ao_list_is_empty(struct ao_list *head) * @return A pointer to the data struct containing the list head. */ #define ao_container_of(ptr, type, member) \ - ((type *)((char *)(ptr) - offsetof(type, member))) + ((type *)((void *) ((char *)(ptr) - offsetof(type, member)))) /** * Alias of ao_container_of diff --git a/src/kernel/ao_pyro.c b/src/kernel/ao_pyro.c index b11d1080..a0881f9e 100644 --- a/src/kernel/ao_pyro.c +++ b/src/kernel/ao_pyro.c @@ -438,7 +438,7 @@ ao_pyro_show(void) if (ao_pyro_values[v].flag & AO_PYRO_8_BIT_VALUE) value = *((uint8_t *) ((char *) pyro + ao_pyro_values[v].offset)); else - value = *((int16_t *) ((char *) pyro + ao_pyro_values[v].offset)); + value = *((int16_t *) (void *) ((char *) pyro + ao_pyro_values[v].offset)); printf ("%6d ", value); } else { printf (" "); @@ -517,7 +517,7 @@ ao_pyro_set(void) } else { if (negative) ao_cmd_lex_i = -ao_cmd_lex_i; - *((int16_t *) ((char *) &pyro_tmp + ao_pyro_values[v].offset)) = ao_cmd_lex_i; + *((int16_t *) (void *) ((char *) &pyro_tmp + ao_pyro_values[v].offset)) = ao_cmd_lex_i; } } } diff --git a/src/kernel/ao_task.h b/src/kernel/ao_task.h index f1dbd654..30b018ff 100644 --- a/src/kernel/ao_task.h +++ b/src/kernel/ao_task.h @@ -26,6 +26,17 @@ #define HAS_TASK_INFO 1 #endif +/* arm stacks must be 32-bit aligned */ +#ifdef __arm__ +#define AO_STACK_ALIGNMENT __attribute__ ((aligned(4))) +#endif +#ifdef SDCC +#define AO_STACK_ALIGNMENT +#endif +#ifdef __AVR__ +#define AO_STACK_ALIGNMENT +#endif + /* An AltOS task */ struct ao_task { __xdata void *wchan; /* current wait channel (NULL if running) */ @@ -37,7 +48,7 @@ struct ao_task { struct ao_list queue; struct ao_list alarm_queue; #endif - uint8_t stack[AO_STACK_SIZE]; /* saved stack */ + uint8_t stack[AO_STACK_SIZE] AO_STACK_ALIGNMENT; /* saved stack */ #if HAS_SAMPLE_PROFILE uint32_t ticks; uint32_t yields; diff --git a/src/stm/Makefile.defs b/src/stm/Makefile.defs index c3d2707f..0ba86f5a 100644 --- a/src/stm/Makefile.defs +++ b/src/stm/Makefile.defs @@ -27,7 +27,7 @@ LIBS=$(PDCLIB_LIBS_M3) -lgcc WARN_FLAGS=-Wall -Wextra -Werror AO_CFLAGS=-I. -I../stm -I../kernel -I../drivers -I../math -I.. $(PDCLIB_INCLUDES) -STM_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m3 -mthumb \ +STM_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m3 -mthumb -Wcast-align \ -ffreestanding -nostdlib $(AO_CFLAGS) $(WARN_FLAGS) LDFLAGS=-L../stm -Wl,-Taltos.ld diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index 18ca20da..a9d0fa34 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -375,7 +375,7 @@ ao_arch_irq_check(void) { static inline void ao_arch_init_stack(struct ao_task *task, void *start) { - uint32_t *sp = (uint32_t *) (task->stack + AO_STACK_SIZE); + uint32_t *sp = (uint32_t *) ((void*) task->stack + AO_STACK_SIZE); uint32_t a = (uint32_t) start; int i; @@ -413,16 +413,11 @@ static inline void ao_arch_save_stack(void) { uint32_t *sp; asm("mov %0,sp" : "=&r" (sp) ); ao_cur_task->sp = (sp); - if ((uint8_t *) sp < &ao_cur_task->stack[0]) - ao_panic (AO_PANIC_STACK); } static inline void ao_arch_restore_stack(void) { - uint32_t sp; - sp = (uint32_t) ao_cur_task->sp; - /* Switch stacks */ - asm("mov sp, %0" : : "r" (sp) ); + asm("mov sp, %0" : : "r" (ao_cur_task->sp) ); /* Restore PRIMASK */ asm("pop {r0}"); diff --git a/src/stm/ao_eeprom_stm.c b/src/stm/ao_eeprom_stm.c index 05f880b8..4f477122 100644 --- a/src/stm/ao_eeprom_stm.c +++ b/src/stm/ao_eeprom_stm.c @@ -83,7 +83,7 @@ ao_intflash_write32(uint16_t pos, uint32_t w) { volatile uint32_t *addr; - addr = (uint32_t *) (stm_eeprom + pos); + addr = (uint32_t *) (void *) (stm_eeprom + pos); /* Write a word to a valid address in the data EEPROM */ *addr = w; @@ -96,7 +96,7 @@ ao_intflash_write8(uint16_t pos, uint8_t d) uint32_t w, *addr, mask; uint8_t shift; - addr = (uint32_t *) (stm_eeprom + (pos & ~3)); + addr = (uint32_t *) (void *) (stm_eeprom + (pos & ~3)); /* Compute word to be written */ shift = (pos & 3) << 3; diff --git a/src/stm/ao_usb_stm.c b/src/stm/ao_usb_stm.c index f2b8ea94..9d72844e 100644 --- a/src/stm/ao_usb_stm.c +++ b/src/stm/ao_usb_stm.c @@ -139,7 +139,7 @@ static inline uint32_t set_toggle(uint32_t current_value, static inline uint32_t *ao_usb_packet_buffer_addr(uint16_t sram_addr) { - return (uint32_t *) (stm_usb_sram + 2 * sram_addr); + return (uint32_t *) (((void *) ((uint8_t *) stm_usb_sram + 2 * sram_addr))); } static inline uint32_t ao_usb_epr_stat_rx(uint32_t epr) { diff --git a/src/stm/stm32l.h b/src/stm/stm32l.h index 463125e2..be1e1d65 100644 --- a/src/stm/stm32l.h +++ b/src/stm/stm32l.h @@ -1961,7 +1961,7 @@ union stm_usb_bdt { #define STM_USB_BDT_SIZE 8 -extern uint8_t stm_usb_sram[]; +extern uint8_t stm_usb_sram[] __attribute__ ((aligned(4))); struct stm_exti { vuint32_t imr; diff --git a/src/stmf0/Makefile-stmf0.defs b/src/stmf0/Makefile-stmf0.defs index 4862f46e..f3296b69 100644 --- a/src/stmf0/Makefile-stmf0.defs +++ b/src/stmf0/Makefile-stmf0.defs @@ -25,7 +25,7 @@ endif ELFTOHEX=$(TOPDIR)/../ao-tools/ao-elftohex/ao-elftohex CC=$(ARM_CC) -WARN_FLAGS=-Wall -Wextra -Werror +WARN_FLAGS=-Wall -Wextra -Werror -Wcast-align AO_CFLAGS=-I. -I$(TOPDIR)/stmf0 -I$(TOPDIR)/kernel -I$(TOPDIR)/drivers -I$(TOPDIR)/product -I$(TOPDIR) -I$(TOPDIR)/math $(PDCLIB_INCLUDES) STMF0_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m0 -mthumb\ diff --git a/src/stmf0/ao_adc_fast.h b/src/stmf0/ao_adc_fast.h index b8b5e003..3f0b0547 100644 --- a/src/stmf0/ao_adc_fast.h +++ b/src/stmf0/ao_adc_fast.h @@ -28,7 +28,7 @@ ao_adc_init(void); /* Total ring size in samples */ #define AO_ADC_RING_SIZE 256 -extern uint16_t ao_adc_ring[AO_ADC_RING_SIZE]; +extern uint16_t ao_adc_ring[AO_ADC_RING_SIZE] __attribute__((aligned(4))); #define ao_adc_ring_step(pos,inc) (((pos) + (inc)) & (AO_ADC_RING_SIZE - 1)) diff --git a/src/stmf0/ao_arch_funcs.h b/src/stmf0/ao_arch_funcs.h index d35bafbd..c38ce41a 100644 --- a/src/stmf0/ao_arch_funcs.h +++ b/src/stmf0/ao_arch_funcs.h @@ -366,7 +366,7 @@ ao_arch_memory_barrier() { static inline void ao_arch_init_stack(struct ao_task *task, void *start) { - uint32_t *sp = (uint32_t *) (task->stack + AO_STACK_SIZE); + uint32_t *sp = (uint32_t *) ((void *) task->stack + AO_STACK_SIZE); uint32_t a = (uint32_t) start; int i; diff --git a/src/stmf0/ao_usb_stm.c b/src/stmf0/ao_usb_stm.c index cbedb996..652b3b6c 100644 --- a/src/stmf0/ao_usb_stm.c +++ b/src/stmf0/ao_usb_stm.c @@ -185,7 +185,7 @@ static inline uint32_t set_toggle(uint32_t current_value, static inline uint16_t *ao_usb_packet_buffer_addr(uint16_t sram_addr) { - return (uint16_t *) (stm_usb_sram + sram_addr); + return (uint16_t *) (void *) (stm_usb_sram + sram_addr); } static inline uint16_t ao_usb_packet_buffer_offset(uint16_t *addr) diff --git a/src/stmf0/stm32f0.h b/src/stmf0/stm32f0.h index 182cd963..1c33f020 100644 --- a/src/stmf0/stm32f0.h +++ b/src/stmf0/stm32f0.h @@ -1996,7 +1996,7 @@ union stm_usb_bdt { #define STM_USB_BDT_SIZE 8 -extern uint8_t stm_usb_sram[]; +extern uint8_t stm_usb_sram[] __attribute__((aligned(4))); struct stm_exti { vuint32_t imr; -- cgit v1.2.3 From f2c7bb5879ba22df05fd1e39f01ea692313306fd Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 10 Jan 2017 17:15:24 +0000 Subject: altos/chaoskey: Add a metainfo for the ChaosKey This provides the information necessary to reflash chaoskey using standard Linux device firmware tooling. --- configure.ac | 4 + src/chaoskey-v1.0/.gitignore | 1 + src/chaoskey-v1.0/Makefile | 12 + src/chaoskey-v1.0/chaoskey-connector.svg | 274 +++++++++++++++++++++ .../org.altusmetrum.ChaosKey.metainfo.xml.in | 46 ++++ 5 files changed, 337 insertions(+) create mode 100644 src/chaoskey-v1.0/chaoskey-connector.svg create mode 100644 src/chaoskey-v1.0/org.altusmetrum.ChaosKey.metainfo.xml.in (limited to 'src') diff --git a/configure.ac b/configure.ac index 0fc946f2..a125033e 100644 --- a/configure.ac +++ b/configure.ac @@ -24,6 +24,9 @@ AC_CONFIG_SRCDIR([src/kernel/ao.h]) AM_INIT_AUTOMAKE([foreign dist-bzip2]) AM_MAINTAINER_MODE +RELEASE_DATE=2017-01-10 +AC_SUBST(RELEASE_DATE) + VERSION_DASH=`echo $VERSION | sed 's/\./-/g'` AC_SUBST(VERSION_DASH) AC_SUBST(ANDROID_VERSION) @@ -515,6 +518,7 @@ AM_CONDITIONAL([INSTALL_SHARED_MIME_INFO], [test x$INSTALL_SHARED_MIME_INFO = xy AC_OUTPUT([ Makefile src/Makedefs +src/chaoskey-v1.0/org.altusmetrum.ChaosKey.metainfo.xml altoslib/Makefile altoslib/AltosVersion.java icon/Makefile diff --git a/src/chaoskey-v1.0/.gitignore b/src/chaoskey-v1.0/.gitignore index b0adba26..9fd59154 100644 --- a/src/chaoskey-v1.0/.gitignore +++ b/src/chaoskey-v1.0/.gitignore @@ -1,2 +1,3 @@ ao_product.h chaoskey-* +*.cab diff --git a/src/chaoskey-v1.0/Makefile b/src/chaoskey-v1.0/Makefile index d9944a12..f6b78d07 100644 --- a/src/chaoskey-v1.0/Makefile +++ b/src/chaoskey-v1.0/Makefile @@ -38,6 +38,8 @@ ALTOS_SRC = \ ao_gpio.c \ ao_product.c +VENDOR=AltusMetrum +PROJECT_NAME=ChaosKey PRODUCT=ChaosKey-hw-1.0-sw-$(VERSION) PRODUCT_DEF=-DCHAOSKEY_V_1_0 IDVENDOR=0x1d50 @@ -48,6 +50,7 @@ CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -g -Os PROGNAME=chaoskey-v1.0 PROG=$(PROGNAME)-$(VERSION).elf HEX=$(PROGNAME)-$(VERSION).ihx +METAINFO=org.altusmetrum.ChaosKey.metainfo.xml SRC=$(ALTOS_SRC) ao_chaoskey.c OBJ=$(SRC:.c=.o) @@ -62,11 +65,20 @@ ao_product.h: ao-make-product.5c ../Version $(OBJ): $(INC) +%.cab: $(PROG) $(HEX) $(METAINFO) + gcab --create --nopath $@ $(PROG) $(HEX) $(METAINFO) + +cab: $(VENDOR)-$(PROJECT_NAME)-$(VERSION).cab + +check: $(METAINFO) + appstream-util validate-relax $(METAINFO) + distclean: clean clean: rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx rm -f ao_product.h + rm -f *.cab install: diff --git a/src/chaoskey-v1.0/chaoskey-connector.svg b/src/chaoskey-v1.0/chaoskey-connector.svg new file mode 100644 index 00000000..671a46bd --- /dev/null +++ b/src/chaoskey-v1.0/chaoskey-connector.svg @@ -0,0 +1,274 @@ + + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + + + + Gnome Symbolic Icon Theme + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/chaoskey-v1.0/org.altusmetrum.ChaosKey.metainfo.xml.in b/src/chaoskey-v1.0/org.altusmetrum.ChaosKey.metainfo.xml.in new file mode 100644 index 00000000..6e391878 --- /dev/null +++ b/src/chaoskey-v1.0/org.altusmetrum.ChaosKey.metainfo.xml.in @@ -0,0 +1,46 @@ + + + + org.altusmetrum.ChaosKey.firmware + ChaosKey + Firmware for the Altus Metrum ChaosKey + +

+ Updating the firmware on your ChaosKey device improves performance and adds + new features. +

+
+ + + b62500d7-c981-595b-a798-eb6cf4d4942b + + https://chaoskey.org/ + CC-BY-4.0 + GPL-2.0 + AltusMetrum + + + + +

+ FIXME before release. +

+
+
+ + + +

+ Change the ADC clock speed to eliminate sampling problems which + cleans up the chaoskey raw data. +

+
+
+
+ + + https://chaoskey.org/chaoskey-connector.svg + Remove the plastic cover, then connect pins 1 and 5 whilst inserting into a USB socket. + + +
-- cgit v1.2.3 From 56d46ceaa1413415f25e47e81036426132f99924 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 31 Oct 2016 16:43:44 -0700 Subject: Add first lisp bits Signed-off-by: Keith Packard --- src/lisp/ao_lisp_atom.c | 107 ++++++++++++++++++ src/lisp/ao_lisp_builtin.c | 21 ++++ src/lisp/ao_lisp_cons.c | 84 +++++++++++++++ src/lisp/ao_lisp_eval.c | 152 ++++++++++++++++++++++++++ src/lisp/ao_lisp_int.c | 21 ++++ src/lisp/ao_lisp_lex.c | 146 +++++++++++++++++++++++++ src/lisp/ao_lisp_mem.c | 246 ++++++++++++++++++++++++++++++++++++++++++ src/lisp/ao_lisp_poly.c | 132 +++++++++++++++++++++++ src/lisp/ao_lisp_prim.c | 71 ++++++++++++ src/lisp/ao_lisp_string.c | 87 +++++++++++++++ src/stmf0/Makefile-stmf0.defs | 2 +- src/test/Makefile | 13 ++- src/test/ao_lisp_test.c | 58 ++++++++++ 13 files changed, 1136 insertions(+), 4 deletions(-) create mode 100644 src/lisp/ao_lisp_atom.c create mode 100644 src/lisp/ao_lisp_builtin.c create mode 100644 src/lisp/ao_lisp_cons.c create mode 100644 src/lisp/ao_lisp_eval.c create mode 100644 src/lisp/ao_lisp_int.c create mode 100644 src/lisp/ao_lisp_lex.c create mode 100644 src/lisp/ao_lisp_mem.c create mode 100644 src/lisp/ao_lisp_poly.c create mode 100644 src/lisp/ao_lisp_prim.c create mode 100644 src/lisp/ao_lisp_string.c create mode 100644 src/test/ao_lisp_test.c (limited to 'src') diff --git a/src/lisp/ao_lisp_atom.c b/src/lisp/ao_lisp_atom.c new file mode 100644 index 00000000..65282142 --- /dev/null +++ b/src/lisp/ao_lisp_atom.c @@ -0,0 +1,107 @@ +/* + * Copyright © 2016 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao_lisp.h" + +static int name_size(char *name) +{ + return sizeof(struct ao_lisp_atom) + strlen(name) + 1; +} + +static int atom_size(void *addr) +{ + struct ao_lisp_atom *atom = addr; + if (!atom) + return 0; + return name_size(atom->name); +} + +static void atom_mark(void *addr) +{ + struct ao_lisp_atom *atom = addr; + + if (atom->next == AO_LISP_ATOM_CONST) + return; + + for (;;) { + ao_lisp_poly_mark(atom->val); + atom = atom->next; + if (!atom) + break; + if (ao_lisp_mark_memory(atom, atom_size(atom))) + break; + } +} + +static void atom_move(void *addr) +{ + struct ao_lisp_atom *atom = addr; + + if (atom->next == AO_LISP_ATOM_CONST) + return; + + for (;;) { + struct ao_lisp_atom *next; + + atom->val = ao_lisp_poly_move(atom->val); + next = ao_lisp_move_memory(atom->next, atom_size(atom->next)); + if (!next) + break; + atom->next = next; + atom = next; + } +} + +const struct ao_lisp_mem_type ao_lisp_atom_type = { + .mark = atom_mark, + .size = atom_size, + .move = atom_move, +}; + +struct ao_lisp_atom *atoms; + +struct ao_lisp_atom * +ao_lisp_atom_intern(char *name) +{ + struct ao_lisp_atom *atom; + int b; + + for (atom = atoms; atom; atom = atom->next) { + if (!strcmp(atom->name, name)) + return atom; + } + for (b = 0; ao_lisp_builtins[b]; b++) + if (!strcmp(ao_lisp_builtins[b]->name, name)) + return (struct ao_lisp_atom *) ao_lisp_builtins[b]; + if (!atoms) + ao_lisp_root_add(&ao_lisp_atom_type, (void **) &atoms); + atom = ao_lisp_alloc(name_size(name)); + if (atom) { + atom->type = AO_LISP_ATOM; + atom->next = atoms; + atoms = atom; + strcpy(atom->name, name); + atom->val = AO_LISP_NIL; + } + return atom; +} + +void +ao_lisp_atom_print(struct ao_lisp_atom *a) +{ + fputs(a->name, stdout); +} diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c new file mode 100644 index 00000000..3752a2c8 --- /dev/null +++ b/src/lisp/ao_lisp_builtin.c @@ -0,0 +1,21 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" + +void +ao_lisp_builtin_print(struct ao_lisp_builtin *b) +{ + printf("[builtin %s]", b->name); +} diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c new file mode 100644 index 00000000..60cbb2f3 --- /dev/null +++ b/src/lisp/ao_lisp_cons.c @@ -0,0 +1,84 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" + +static void cons_mark(void *addr) +{ + struct ao_lisp_cons *cons = addr; + + for (;;) { + ao_lisp_poly_mark(cons->car); + cons = cons->cdr; + if (!cons) + break; + if (ao_lisp_mark_memory(cons, sizeof (struct ao_lisp_cons))) + break; + } +} + +static int cons_size(void *addr) +{ + (void) addr; + return sizeof (struct ao_lisp_cons); +} + +static void cons_move(void *addr) +{ + struct ao_lisp_cons *cons = addr; + + for (;;) { + struct ao_lisp_cons *cdr; + + cons->car = ao_lisp_poly_move(cons->car); + cdr = ao_lisp_move_memory(cons->cdr, sizeof (struct ao_lisp_cons)); + if (!cdr) + break; + cons->cdr = cdr; + cons = cdr; + } +} + +const struct ao_lisp_mem_type ao_lisp_cons_type = { + .mark = cons_mark, + .size = cons_size, + .move = cons_move, +}; + +struct ao_lisp_cons * +ao_lisp_cons(ao_lisp_poly car, struct ao_lisp_cons *cdr) +{ + struct ao_lisp_cons *cons = ao_lisp_alloc(sizeof (struct ao_lisp_cons)); + if (!cons) + return NULL; + cons->car = car; + cons->cdr = cdr; + return cons; +} + +void +ao_lisp_cons_print(struct ao_lisp_cons *cons) +{ + int first = 1; + printf("("); + while (cons) { + if (!first) + printf(" "); + fflush(stdout); + ao_lisp_poly_print(cons->car); + cons = cons->cdr; + first = 0; + } + printf(")"); +} diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c new file mode 100644 index 00000000..531e3b72 --- /dev/null +++ b/src/lisp/ao_lisp_eval.c @@ -0,0 +1,152 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" + +/* + * Non-recursive eval + * + * Plan: walk actuals, construct formals + * + * stack > save > actuals > actual_1 + * v v + * formals . > actual_2 + */ + +static struct ao_lisp_cons *stack; +static struct ao_lisp_cons *actuals; +static struct ao_lisp_cons *formals; +static struct ao_lisp_cons *formals_tail; +static uint8_t been_here; + +ao_lisp_poly +ao_lisp_eval(ao_lisp_poly v) +{ + struct ao_lisp_cons *formal; + int cons = 0; + + if (!been_here) { + been_here = 1; + ao_lisp_root_add(&ao_lisp_cons_type, &stack); + ao_lisp_root_add(&ao_lisp_cons_type, &actuals); + ao_lisp_root_add(&ao_lisp_cons_type, &formals); + ao_lisp_root_add(&ao_lisp_cons_type, &formals_tail); + } + stack = 0; + actuals = 0; + formals = 0; + formals_tail = 0; + for (;;) { + + /* Build stack frames for each list */ + while (ao_lisp_poly_type(v) == AO_LISP_CONS) { + if (v == AO_LISP_NIL) + break; + + /* Push existing frame on the stack */ + if (cons++) { + struct ao_lisp_cons *frame; + + frame = ao_lisp_cons(ao_lisp_cons_poly(actuals), formals); + stack = ao_lisp_cons(ao_lisp_cons_poly(frame), stack); + } + actuals = ao_lisp_poly_cons(v); + formals = NULL; + formals_tail = NULL; + v = actuals->car; + + printf("start: stack"); ao_lisp_cons_print(stack); printf("\n"); + printf("start: actuals"); ao_lisp_cons_print(actuals); printf("\n"); + printf("start: formals"); ao_lisp_cons_print(formals); printf("\n"); + } + + /* Evaluate primitive types */ + + switch (ao_lisp_poly_type(v)) { + case AO_LISP_INT: + case AO_LISP_STRING: + break; + case AO_LISP_ATOM: + v = ao_lisp_poly_atom(v)->val; + break; + } + + for (;;) { + printf("add formal: "); ao_lisp_poly_print(v); printf("\n"); + + formal = ao_lisp_cons(v, NULL); + if (formals_tail) + formals_tail->cdr = formal; + else + formals = formal; + formals_tail = formal; + actuals = actuals->cdr; + + printf("formals: "); + ao_lisp_cons_print(formals); + printf("\n"); + printf("actuals: "); + ao_lisp_cons_print(actuals); + printf("\n"); + + /* Process all of the arguments */ + if (actuals) { + v = actuals->car; + printf ("actual: "); ao_lisp_poly_print(v); printf("\n"); + break; + } + + v = formals->car; + + /* Evaluate the resulting list */ + if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) { + struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v); + + v = b->func(formals->cdr); + + printf ("eval: "); + ao_lisp_cons_print(formals); + printf(" -> "); + ao_lisp_poly_print(v); + printf ("\n"); + } else { + printf ("invalid eval\n"); + } + + if (--cons) { + struct ao_lisp_cons *frame; + + /* Pop the previous frame off the stack */ + frame = ao_lisp_poly_cons(stack->car); + actuals = ao_lisp_poly_cons(frame->car); + formals = frame->cdr; + + /* Recompute the tail of the formals list */ + for (formal = formals; formal->cdr != NULL; formal = formal->cdr); + formals_tail = formal; + + stack = stack->cdr; + printf("stack pop: stack"); ao_lisp_cons_print(stack); printf("\n"); + printf("stack pop: actuals"); ao_lisp_cons_print(actuals); printf("\n"); + printf("stack pop: formals"); ao_lisp_cons_print(formals); printf("\n"); + } else { + printf("done func\n"); + break; + } + } + if (!cons) + break; + } + return v; +} diff --git a/src/lisp/ao_lisp_int.c b/src/lisp/ao_lisp_int.c new file mode 100644 index 00000000..6ee3096d --- /dev/null +++ b/src/lisp/ao_lisp_int.c @@ -0,0 +1,21 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" + +void +ao_lisp_int_print(int i) +{ + printf("%d", i); +} diff --git a/src/lisp/ao_lisp_lex.c b/src/lisp/ao_lisp_lex.c new file mode 100644 index 00000000..d62db872 --- /dev/null +++ b/src/lisp/ao_lisp_lex.c @@ -0,0 +1,146 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" + +const uint32_t classTable[256] = { + IGNORE, /* ^@ */ + IGNORE, /* ^A */ + IGNORE, /* ^B */ + IGNORE, /* ^C */ + IGNORE, /* ^D */ + IGNORE, /* ^E */ + IGNORE, /* ^F */ + IGNORE, /* ^G */ + IGNORE, /* ^H */ + WHITE, /* ^I */ + WHITE, /* ^J */ + WHITE, /* ^K */ + WHITE, /* ^L */ + WHITE, /* ^M */ + IGNORE, /* ^N */ + IGNORE, /* ^O */ + IGNORE, /* ^P */ + IGNORE, /* ^Q */ + IGNORE, /* ^R */ + IGNORE, /* ^S */ + IGNORE, /* ^T */ + IGNORE, /* ^U */ + IGNORE, /* ^V */ + IGNORE, /* ^W */ + IGNORE, /* ^X */ + IGNORE, /* ^Y */ + IGNORE, /* ^Z */ + IGNORE, /* ^[ */ + IGNORE, /* ^\ */ + IGNORE, /* ^] */ + IGNORE, /* ^^ */ + IGNORE, /* ^_ */ + PRINTABLE|WHITE, /* */ + PRINTABLE, /* ! */ + PRINTABLE|STRINGC, /* " */ + PRINTABLE|COMMENT, /* # */ + PRINTABLE, /* $ */ + PRINTABLE, /* % */ + PRINTABLE, /* & */ + PRINTABLE|QUOTEC, /* ' */ + PRINTABLE|BRA, /* ( */ + PRINTABLE|KET, /* ) */ + PRINTABLE, /* * */ + PRINTABLE|SIGN, /* + */ + PRINTABLE, /* , */ + PRINTABLE|SIGN, /* - */ + PRINTABLE|DOT, /* . */ + PRINTABLE, /* / */ + PRINTABLE|DIGIT, /* 0 */ + PRINTABLE|DIGIT, /* 1 */ + PRINTABLE|DIGIT, /* 2 */ + PRINTABLE|DIGIT, /* 3 */ + PRINTABLE|DIGIT, /* 4 */ + PRINTABLE|DIGIT, /* 5 */ + PRINTABLE|DIGIT, /* 6 */ + PRINTABLE|DIGIT, /* 7 */ + PRINTABLE|DIGIT, /* 8 */ + PRINTABLE|DIGIT, /* 9 */ + PRINTABLE, /* : */ + PRINTABLE|COMMENT, /* ; */ + PRINTABLE, /* < */ + PRINTABLE, /* = */ + PRINTABLE, /* > */ + PRINTABLE, /* ? */ + PRINTABLE, /* @ */ + PRINTABLE, /* A */ + PRINTABLE, /* B */ + PRINTABLE, /* C */ + PRINTABLE, /* D */ + PRINTABLE|EXP, /* E */ + PRINTABLE, /* F */ + PRINTABLE, /* G */ + PRINTABLE, /* H */ + PRINTABLE, /* I */ + PRINTABLE, /* J */ + PRINTABLE, /* K */ + PRINTABLE, /* L */ + PRINTABLE, /* M */ + PRINTABLE, /* N */ + PRINTABLE, /* O */ + PRINTABLE, /* P */ + PRINTABLE, /* Q */ + PRINTABLE, /* R */ + PRINTABLE, /* S */ + PRINTABLE, /* T */ + PRINTABLE, /* U */ + PRINTABLE, /* V */ + PRINTABLE, /* W */ + PRINTABLE, /* X */ + PRINTABLE, /* Y */ + PRINTABLE, /* Z */ + PRINTABLE|BRA, /* [ */ + PRINTABLE|BACKSLASH, /* \ */ + PRINTABLE|KET, /* ] */ + PRINTABLE, /* ^ */ + PRINTABLE, /* _ */ + PRINTABLE, /* ` */ + PRINTABLE, /* a */ + PRINTABLE, /* b */ + PRINTABLE, /* c */ + PRINTABLE, /* d */ + PRINTABLE|EXP, /* e */ + PRINTABLE, /* f */ + PRINTABLE, /* g */ + PRINTABLE, /* h */ + PRINTABLE, /* i */ + PRINTABLE, /* j */ + PRINTABLE, /* k */ + PRINTABLE, /* l */ + PRINTABLE, /* m */ + PRINTABLE, /* n */ + PRINTABLE, /* o */ + PRINTABLE, /* p */ + PRINTABLE, /* q */ + PRINTABLE, /* r */ + PRINTABLE, /* s */ + PRINTABLE, /* t */ + PRINTABLE, /* u */ + PRINTABLE, /* v */ + PRINTABLE, /* w */ + PRINTABLE, /* x */ + PRINTABLE, /* y */ + PRINTABLE, /* z */ + PRINTABLE|BRA, /* { */ + PRINTABLE|VBAR, /* | */ + PRINTABLE|KET, /* } */ + PRINTABLE|TWIDDLE, /* ~ */ + IGNORE, /* ^? */ +}; diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c new file mode 100644 index 00000000..f6a108e9 --- /dev/null +++ b/src/lisp/ao_lisp_mem.c @@ -0,0 +1,246 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" +#include + +uint8_t ao_lisp_pool[AO_LISP_POOL]; + +struct ao_lisp_root { + void **addr; + const struct ao_lisp_mem_type *type; +}; + +static struct ao_lisp_root ao_lisp_root[AO_LISP_ROOT]; + +static uint8_t ao_lisp_busy[AO_LISP_POOL / 32]; + +static uint8_t ao_lisp_moving[AO_LISP_POOL / 32]; + +static uint16_t ao_lisp_top; + +static inline void mark(uint8_t *tag, int offset) { + int byte = offset >> 5; + int bit = (offset >> 2) & 7; + tag[byte] |= (1 << bit); +} + +static inline void clear(uint8_t *tag, int offset) { + int byte = offset >> 5; + int bit = (offset >> 2) & 7; + tag[byte] &= ~(1 << bit); +} + +static inline int busy(uint8_t *tag, int offset) { + int byte = offset >> 5; + int bit = (offset >> 2) & 7; + return (tag[byte] >> bit) & 1; +} + +static inline int min(int a, int b) { return a < b ? a : b; } +static inline int max(int a, int b) { return a > b ? a : b; } + +static inline int limit(int offset) { + return min(AO_LISP_POOL, max(offset, 0)); +} + +static int +mark_object(uint8_t *tag, void *addr, int size) { + int base; + int bound; + if (!addr) + return 1; + + base = (uint8_t *) addr - ao_lisp_pool; + bound = base + size; + + base = limit(base); + bound = limit(bound); + if (busy(tag, base)) + return 1; + while (base < bound) { + mark(tag, base); + base += 4; + } + return 0; +} + +static int +clear_object(uint8_t *tag, void *addr, int size) { + int base; + int bound; + if (!addr) + return 1; + + base = (uint8_t *) addr - ao_lisp_pool; + bound = base + size; + + base = limit(base); + bound = limit(bound); + if (!busy(tag, base)) + return 1; + while (base < bound) { + clear(tag, base); + base += 4; + } + return 0; +} + +static void *move_old, *move_new; +static int move_size; + +static void +move_object(void) +{ + int i; + + memset(ao_lisp_moving, '\0', sizeof (ao_lisp_moving)); + for (i = 0; i < AO_LISP_ROOT; i++) + if (ao_lisp_root[i].addr) { + void *new; + new = ao_lisp_move(ao_lisp_root[i].type, *ao_lisp_root[i].addr); + if (new) + *ao_lisp_root[i].addr = new; + } +} + +static void +collect(void) +{ + int i; + + printf("collect\n"); + /* Mark */ + memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy)); + for (i = 0; i < AO_LISP_ROOT; i++) + if (ao_lisp_root[i].addr) + ao_lisp_mark(ao_lisp_root[i].type, *ao_lisp_root[i].addr); + + /* Compact */ + ao_lisp_top = 0; + for (i = 0; i < AO_LISP_POOL; i += 4) { + if (!busy(ao_lisp_busy, i)) + break; + } + ao_lisp_top = i; + while(i < AO_LISP_POOL) { + if (busy(ao_lisp_busy, i)) { + move_old = &ao_lisp_pool[i]; + move_new = &ao_lisp_pool[ao_lisp_top]; + move_size = 0; + move_object(); + clear_object(ao_lisp_busy, move_old, move_size); + i += move_size; + ao_lisp_top += move_size; + } else { + i += 4; + } + } +} + + +void +ao_lisp_mark(const struct ao_lisp_mem_type *type, void *addr) +{ + if (mark_object(ao_lisp_busy, addr, type->size(addr))) + return; + type->mark(addr); +} + +int +ao_lisp_mark_memory(void *addr, int size) +{ + return mark_object(ao_lisp_busy, addr, size); +} + +static void * +check_move(void *addr, int size) +{ + if (addr == move_old) { + memmove(move_new, move_old, size); + move_size = (size + 3) & ~3; + addr = move_new; + } + return addr; +} + +void * +ao_lisp_move(const struct ao_lisp_mem_type *type, void *addr) +{ + int size = type->size(addr); + + if (!addr) + return NULL; + + addr = check_move(addr, size); + if (mark_object(ao_lisp_moving, addr, size)) + return addr; + type->move(addr); + return addr; +} + +void * +ao_lisp_move_memory(void *addr, int size) +{ + if (!addr) + return NULL; + + addr = check_move(addr, size); + if (mark_object(ao_lisp_moving, addr, size)) + return NULL; + return addr; +} + +void * +ao_lisp_alloc(int size) +{ + void *addr; + + size = (size + 3) & ~3; + if (ao_lisp_top + size > AO_LISP_POOL) { + collect(); + if (ao_lisp_top + size > AO_LISP_POOL) + return NULL; + } + addr = ao_lisp_pool + ao_lisp_top; + ao_lisp_top += size; + return addr; +} + +int +ao_lisp_root_add(const struct ao_lisp_mem_type *type, void *addr) +{ + int i; + for (i = 0; i < AO_LISP_ROOT; i++) { + if (!ao_lisp_root[i].addr) { + ao_lisp_root[i].addr = addr; + ao_lisp_root[i].type = type; + return 1; + } + } + return 0; +} + +void +ao_lisp_root_clear(void *addr) +{ + int i; + for (i = 0; i < AO_LISP_ROOT; i++) { + if (ao_lisp_root[i].addr == addr) { + ao_lisp_root[i].addr = 0; + ao_lisp_root[i].type = 0; + break; + } + } +} diff --git a/src/lisp/ao_lisp_poly.c b/src/lisp/ao_lisp_poly.c new file mode 100644 index 00000000..1855d945 --- /dev/null +++ b/src/lisp/ao_lisp_poly.c @@ -0,0 +1,132 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" + +enum math_op { math_plus, math_minus, math_times, math_divide, math_mod }; + +ao_lisp_poly +ao_lisp_math(struct ao_lisp_cons *cons, enum math_op op) +{ + ao_lisp_poly ret = AO_LISP_NIL; + + while (cons) { + ao_lisp_poly car = cons->car; + uint8_t rt = ao_lisp_poly_type(ret); + uint8_t ct = ao_lisp_poly_type(car); + + cons = cons->cdr; + + if (rt == AO_LISP_NIL) + ret = car; + + else if (rt == AO_LISP_INT && ct == AO_LISP_INT) { + int r = ao_lisp_poly_int(ret); + int c = ao_lisp_poly_int(car); + + switch(op) { + case math_plus: + r += c; + break; + case math_minus: + r -= c; + break; + case math_times: + r *= c; + break; + case math_divide: + if (c == 0) + return AO_LISP_NIL; + r /= c; + break; + case math_mod: + if (c == 0) + return AO_LISP_NIL; + r %= c; + break; + } + ret = ao_lisp_int_poly(r); + } + + else if (rt == AO_LISP_STRING && ct == AO_LISP_STRING && op == math_plus) + ret = ao_lisp_string_poly(ao_lisp_string_cat(ao_lisp_poly_string(ret), + ao_lisp_poly_string(car))); + else { + /* XXX exception */ + return AO_LISP_NIL; + } + } + return ret; +} + +ao_lisp_poly +ao_lisp_plus(struct ao_lisp_cons *cons) +{ + return ao_lisp_math(cons, math_plus); +} + +ao_lisp_poly +ao_lisp_minus(struct ao_lisp_cons *cons) +{ + return ao_lisp_math(cons, math_minus); +} + +ao_lisp_poly +ao_lisp_times(struct ao_lisp_cons *cons) +{ + return ao_lisp_math(cons, math_times); +} + +ao_lisp_poly +ao_lisp_divide(struct ao_lisp_cons *cons) +{ + return ao_lisp_math(cons, math_divide); +} + +ao_lisp_poly +ao_lisp_mod(struct ao_lisp_cons *cons) +{ + return ao_lisp_math(cons, math_mod); +} + +static const struct ao_lisp_builtin builtin_plus = { + .type = AO_LISP_BUILTIN, + .func = ao_lisp_plus, + .name = "+" +}; + +static const struct ao_lisp_atom atom_plus = { + .type = AO_LISP_ATOM, + .val = AO_LISP_OTHER_POLY(&builtin_plus), + .next = AO_LISP_ATOM_CONST, + .name = "plus" +}; + +/* +static const struct ao_lisp_builtin builtin_minus = { + .type = AO_LISP_BUILTIN, + .func = ao_lisp_minus +}; + +static const struct ao_lisp_builtin builtin_times = { + .type = AO_LISP_BUILTIN, + .func = ao_lisp_times +}; + +*/ + +const struct ao_lisp_atom const *ao_lisp_builtins[] = { + &atom_plus, + 0 +}; diff --git a/src/lisp/ao_lisp_prim.c b/src/lisp/ao_lisp_prim.c new file mode 100644 index 00000000..ccfd2be4 --- /dev/null +++ b/src/lisp/ao_lisp_prim.c @@ -0,0 +1,71 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" + +ao_lisp_poly +ao_lisp_poly_print(ao_lisp_poly p) +{ + switch (ao_lisp_poly_type(p)) { + case AO_LISP_CONS: + ao_lisp_cons_print(ao_lisp_poly_cons(p)); + break; + case AO_LISP_STRING: + ao_lisp_string_print(ao_lisp_poly_string(p)); + break; + case AO_LISP_INT: + ao_lisp_int_print(ao_lisp_poly_int(p)); + break; + case AO_LISP_ATOM: + ao_lisp_atom_print(ao_lisp_poly_atom(p)); + break; + case AO_LISP_BUILTIN: + ao_lisp_builtin_print(ao_lisp_poly_builtin(p)); + break; + } + return AO_LISP_NIL; +} + +void +ao_lisp_poly_mark(ao_lisp_poly p) +{ + switch (ao_lisp_poly_type(p)) { + case AO_LISP_CONS: + ao_lisp_mark(&ao_lisp_cons_type, ao_lisp_poly_cons(p)); + break; + case AO_LISP_STRING: + ao_lisp_mark(&ao_lisp_string_type, ao_lisp_poly_string(p)); + break; + case AO_LISP_ATOM: + ao_lisp_mark(&ao_lisp_atom_type, ao_lisp_poly_atom(p)); + break; + } +} + +ao_lisp_poly +ao_lisp_poly_move(ao_lisp_poly p) +{ + switch (ao_lisp_poly_type(p)) { + case AO_LISP_CONS: + p = ao_lisp_cons_poly(ao_lisp_move(&ao_lisp_cons_type, ao_lisp_poly_cons(p))); + break; + case AO_LISP_STRING: + p = ao_lisp_string_poly(ao_lisp_move(&ao_lisp_string_type, ao_lisp_poly_string(p))); + break; + case AO_LISP_ATOM: + p = ao_lisp_atom_poly(ao_lisp_move(&ao_lisp_atom_type, ao_lisp_poly_atom(p))); + break; + } + return p; +} diff --git a/src/lisp/ao_lisp_string.c b/src/lisp/ao_lisp_string.c new file mode 100644 index 00000000..87024271 --- /dev/null +++ b/src/lisp/ao_lisp_string.c @@ -0,0 +1,87 @@ +/* + * Copyright © 2016 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao_lisp.h" + +static void string_mark(void *addr) +{ + (void) addr; +} + +static int string_size(void *addr) +{ + if (!addr) + return 0; + return strlen(addr) + 1; +} + +static void string_move(void *addr) +{ + (void) addr; +} + +char * +ao_lisp_string_new(int len) { + char *a = ao_lisp_alloc(len + 1); + if (!a) + return NULL; + a[len] = '\0'; + return a; +} + +char * +ao_lisp_string_cat(char *a, char *b) +{ + int alen = strlen(a); + int blen = strlen(b); + char *r = ao_lisp_alloc(alen + blen + 1); + if (!r) + return NULL; + strcpy(r, a); + strcpy(r+alen, b); + return r; +} + +const struct ao_lisp_mem_type ao_lisp_string_type = { + .mark = string_mark, + .size = string_size, + .move = string_move, +}; + +void +ao_lisp_string_print(char *s) +{ + char c; + putchar('"'); + while ((c = *s++)) { + switch (c) { + case '\n': + printf ("\\n"); + break; + case '\r': + printf ("\\r"); + break; + case '\t': + printf ("\\t"); + break; + default: + putchar(c); + break; + } + } + putchar('"'); +} diff --git a/src/stmf0/Makefile-stmf0.defs b/src/stmf0/Makefile-stmf0.defs index f3296b69..0ccfbe2a 100644 --- a/src/stmf0/Makefile-stmf0.defs +++ b/src/stmf0/Makefile-stmf0.defs @@ -4,7 +4,7 @@ endif include $(TOPDIR)/Makedefs -vpath % $(TOPDIR)/stmf0:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR/aes):$(TOPDIR):$(TOPDIR)/math +vpath % $(TOPDIR)/stmf0:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR/aes):$(TOPDIR):$(TOPDIR)/math:$(TOPDIR)/lisp vpath make-altitude $(TOPDIR)/util vpath make-kalman $(TOPDIR)/util vpath kalman.5c $(TOPDIR)/kalman diff --git a/src/test/Makefile b/src/test/Makefile index 02e1d22b..a409ae13 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -1,16 +1,16 @@ -vpath % ..:../kernel:../drivers:../util:../micropeak:../aes:../product +vpath % ..:../kernel:../drivers:../util:../micropeak:../aes:../product:../lisp PROGS=ao_flight_test ao_flight_test_baro ao_flight_test_accel ao_flight_test_noisy_accel ao_flight_test_mm \ ao_flight_test_metrum \ ao_gps_test ao_gps_test_skytraq ao_gps_test_ublox ao_convert_test ao_convert_pa_test ao_fec_test \ ao_aprs_test ao_micropeak_test ao_fat_test ao_aes_test ao_int64_test \ - ao_ms5607_convert_test ao_quaternion_test + ao_ms5607_convert_test ao_quaternion_test ao_lisp_test INCS=ao_kalman.h ao_ms5607.h ao_log.h ao_data.h altitude-pa.h altitude.h ao_quaternion.h KALMAN=make-kalman -CFLAGS=-I.. -I. -I../kernel -I../drivers -I../micropeak -I../product -O0 -g -Wall +CFLAGS=-I.. -I. -I../kernel -I../drivers -I../micropeak -I../product -I../lisp -O0 -g -Wall all: $(PROGS) ao_aprs_data.wav @@ -88,3 +88,10 @@ ao_ms5607_convert_test: ao_ms5607_convert_test.c ao_ms5607_convert_8051.c ao_int ao_quaternion_test: ao_quaternion_test.c ao_quaternion.h cc $(CFLAGS) -o $@ ao_quaternion_test.c -lm + +AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o ao_lisp_lex.o ao_lisp_cons.o ao_lisp_string.o ao_lisp_atom.o ao_lisp_int.o ao_lisp_prim.o ao_lisp_eval.o ao_lisp_poly.o ao_lisp_builtin.o + +ao_lisp_test: $(AO_LISP_OBJS) + cc $(CFLAGS) -o $@ $(AO_LISP_OBJS) + +$(AO_LISP_OBJS): ao_lisp.h diff --git a/src/test/ao_lisp_test.c b/src/test/ao_lisp_test.c new file mode 100644 index 00000000..bbadfa75 --- /dev/null +++ b/src/test/ao_lisp_test.c @@ -0,0 +1,58 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" +#include + +static struct ao_lisp_cons *list; +static char *string; + +int +main (int argc, char **argv) +{ + int i, j; + struct ao_lisp_atom *atom; + ao_lisp_root_add(&ao_lisp_cons_type, (void **) &list); + ao_lisp_root_add(&ao_lisp_string_type, (void **) &string); + + /* allocator test */ + for (j = 0; j < 10; j++) { + list = 0; + string = ao_lisp_string_new(0); + for (i = 0; i < 7; i++) { + string = ao_lisp_string_cat(string, "a"); + list = ao_lisp_cons(ao_lisp_string_poly(string), list); + list = ao_lisp_cons(ao_lisp_int_poly(i), list); + atom = ao_lisp_atom_intern("ant"); + atom->val = ao_lisp_cons_poly(list); + list = ao_lisp_cons(ao_lisp_atom_poly(atom), list); + } + ao_lisp_poly_print(ao_lisp_cons_poly(list)); + printf("\n"); + } + + atom = ao_lisp_atom_intern("ant"); + atom->val = ao_lisp_string_poly(ao_lisp_string_cat("hello world", "")); + + list = ao_lisp_cons(ao_lisp_atom_poly(ao_lisp_atom_intern("plus")), + ao_lisp_cons(ao_lisp_cons_poly(ao_lisp_cons(ao_lisp_atom_poly(ao_lisp_atom_intern("plus")), + ao_lisp_cons(ao_lisp_int_poly(3), + ao_lisp_cons(ao_lisp_int_poly(4), NULL)))), + ao_lisp_cons(ao_lisp_int_poly(2), NULL))); + printf("list: "); + ao_lisp_poly_print(ao_lisp_cons_poly(list)); + printf ("\n"); + ao_lisp_poly_print(ao_lisp_eval(ao_lisp_cons_poly(list))); + printf ("\n"); +} -- cgit v1.2.3 From e2f4d25cd6f6f3787d4ee99264732d5b2ce23d4c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 31 Oct 2016 18:53:09 -0700 Subject: altos: Add lisp reader --- src/lisp/ao_lisp.h | 242 +++++++++++++++++++++++++ src/lisp/ao_lisp_eval.c | 52 +++--- src/lisp/ao_lisp_lex.c | 130 -------------- src/lisp/ao_lisp_mem.c | 1 - src/lisp/ao_lisp_read.c | 448 ++++++++++++++++++++++++++++++++++++++++++++++ src/lisp/ao_lisp_read.h | 49 +++++ src/lisp/ao_lisp_string.c | 12 ++ src/test/Makefile | 2 +- src/test/ao_lisp_test.c | 9 + 9 files changed, 792 insertions(+), 153 deletions(-) create mode 100644 src/lisp/ao_lisp.h create mode 100644 src/lisp/ao_lisp_read.c create mode 100644 src/lisp/ao_lisp_read.h (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h new file mode 100644 index 00000000..6667dcc2 --- /dev/null +++ b/src/lisp/ao_lisp.h @@ -0,0 +1,242 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _AO_LISP_H_ +#define _AO_LISP_H_ + +#include +#include +#include + + +# define AO_LISP_CONS 0 +# define AO_LISP_INT 1 +# define AO_LISP_STRING 2 +# define AO_LISP_OTHER 3 + +# define AO_LISP_ATOM 4 +# define AO_LISP_BUILTIN 5 + +# define AO_LISP_NIL 0 + +#define AO_LISP_POOL 1024 +#define AO_LISP_ROOT 16 + +static inline void *ao_lisp_set_ref(void *addr) { + return (void *) ((intptr_t)addr | 1); +} + +static inline void *ao_lisp_clear_ref(void *addr) { + return (void *) ((intptr_t)addr & ~1); +} + +extern uint8_t ao_lisp_pool[AO_LISP_POOL]; + +struct ao_lisp_mem_type { + void (*mark)(void *addr); + int (*size)(void *addr); + void (*move)(void *addr); +}; + +typedef intptr_t ao_lisp_poly; + +struct ao_lisp_cons { + ao_lisp_poly car; + struct ao_lisp_cons *cdr; +}; + +struct ao_lisp_atom { + uint8_t type; + ao_lisp_poly val; + struct ao_lisp_atom *next; + char name[]; +}; + +#define AO_LISP_ATOM_CONST ((struct ao_lisp_atom *) (intptr_t) 1) + +extern const struct ao_lisp_atom *ao_lisp_builtins[]; + +struct ao_lisp_builtin { + uint8_t type; + ao_lisp_poly (*func)(struct ao_lisp_cons *cons); + char name[]; +}; + +static inline void * +ao_lisp_poly_other(ao_lisp_poly poly) { + return (void *) (poly - AO_LISP_OTHER); +} + +static const inline ao_lisp_poly +ao_lisp_other_poly(const void *other) +{ + return (ao_lisp_poly) other + AO_LISP_OTHER; +} + +#define AO_LISP_OTHER_POLY(other) ((ao_lisp_poly)(other) + AO_LISP_OTHER) + +static inline int ao_lisp_poly_type(ao_lisp_poly poly) { + int type = poly & 3; + if (type == AO_LISP_OTHER) + return *((uint8_t *) ao_lisp_poly_other(poly)); + return type; +} + +static inline struct ao_lisp_cons * +ao_lisp_poly_cons(ao_lisp_poly poly) +{ + return (struct ao_lisp_cons *) (poly - AO_LISP_CONS); +} + +static inline ao_lisp_poly +ao_lisp_cons_poly(struct ao_lisp_cons *cons) +{ + return (ao_lisp_poly) cons + AO_LISP_CONS; +} + +static inline int +ao_lisp_poly_int(ao_lisp_poly poly) +{ + return (int) (poly >> 2); +} + +static inline ao_lisp_poly +ao_lisp_int_poly(int i) +{ + return ((ao_lisp_poly) i << 2) + AO_LISP_INT; +} + +static inline char * +ao_lisp_poly_string(ao_lisp_poly poly) +{ + return (char *) (poly - AO_LISP_STRING); +} + +static inline ao_lisp_poly +ao_lisp_string_poly(char *s) { + return (ao_lisp_poly) s + AO_LISP_STRING; +} + +static inline struct ao_lisp_atom * +ao_lisp_poly_atom(ao_lisp_poly poly) +{ + return (struct ao_lisp_atom *) (poly - AO_LISP_OTHER); +} + +static inline ao_lisp_poly +ao_lisp_atom_poly(struct ao_lisp_atom *a) +{ + return (ao_lisp_poly) a + AO_LISP_OTHER; +} + +static inline struct ao_lisp_builtin * +ao_lisp_poly_builtin(ao_lisp_poly poly) +{ + return (struct ao_lisp_builtin *) (poly - AO_LISP_OTHER); +} + +static inline ao_lisp_poly +ao_lisp_builtin_poly(struct ao_lisp_builtin *b) +{ + return (ao_lisp_poly) b + AO_LISP_OTHER; +} + +/* memory functions */ + +void +ao_lisp_mark(const struct ao_lisp_mem_type *type, void *addr); + +/* returns 1 if the object was already marked */ +int +ao_lisp_mark_memory(void *addr, int size); + +void * +ao_lisp_move(const struct ao_lisp_mem_type *type, void *addr); + +/* returns NULL if the object was already moved */ +void * +ao_lisp_move_memory(void *addr, int size); + +void * +ao_lisp_alloc(int size); + +int +ao_lisp_root_add(const struct ao_lisp_mem_type *type, void *addr); + +void +ao_lisp_root_clear(void *addr); + +/* cons */ +extern const struct ao_lisp_mem_type ao_lisp_cons_type; + +struct ao_lisp_cons * +ao_lisp_cons(ao_lisp_poly car, struct ao_lisp_cons *cdr); + +void +ao_lisp_cons_print(struct ao_lisp_cons *cons); + +/* string */ +extern const struct ao_lisp_mem_type ao_lisp_string_type; + +char * +ao_lisp_string_new(int len); + +char * +ao_lisp_string_copy(char *a); + +char * +ao_lisp_string_cat(char *a, char *b); + +void +ao_lisp_string_print(char *s); + +/* atom */ +extern const struct ao_lisp_mem_type ao_lisp_atom_type; + +void +ao_lisp_atom_init(void); + +void +ao_lisp_atom_print(struct ao_lisp_atom *atom); + +struct ao_lisp_atom * +ao_lisp_atom_intern(char *name); + +/* int */ +void +ao_lisp_int_print(int i); + +/* prim */ +ao_lisp_poly +ao_lisp_poly_print(ao_lisp_poly p); + +void +ao_lisp_poly_mark(ao_lisp_poly p); + +ao_lisp_poly +ao_lisp_poly_move(ao_lisp_poly p); + +/* eval */ +ao_lisp_poly +ao_lisp_eval(ao_lisp_poly p); + +/* builtin */ +void +ao_lisp_builtin_print(struct ao_lisp_builtin *b); + +/* read */ +ao_lisp_poly +ao_lisp_read(void); + +#endif /* _AO_LISP_H_ */ diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index 531e3b72..23908e64 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -30,6 +30,16 @@ static struct ao_lisp_cons *formals; static struct ao_lisp_cons *formals_tail; static uint8_t been_here; +#if 0 +#define DBG(...) printf(__VA_ARGS__) +#define DBG_CONS(a) ao_lisp_cons_print(a) +#define DBG_POLY(a) ao_lisp_poly_print(a) +#else +#define DBG(...) +#define DBG_CONS(a) +#define DBG_POLY(a) +#endif + ao_lisp_poly ao_lisp_eval(ao_lisp_poly v) { @@ -66,9 +76,9 @@ ao_lisp_eval(ao_lisp_poly v) formals_tail = NULL; v = actuals->car; - printf("start: stack"); ao_lisp_cons_print(stack); printf("\n"); - printf("start: actuals"); ao_lisp_cons_print(actuals); printf("\n"); - printf("start: formals"); ao_lisp_cons_print(formals); printf("\n"); + DBG("start: stack"); DBG_CONS(stack); DBG("\n"); + DBG("start: actuals"); DBG_CONS(actuals); DBG("\n"); + DBG("start: formals"); DBG_CONS(formals); DBG("\n"); } /* Evaluate primitive types */ @@ -83,7 +93,7 @@ ao_lisp_eval(ao_lisp_poly v) } for (;;) { - printf("add formal: "); ao_lisp_poly_print(v); printf("\n"); + DBG("add formal: "); DBG_POLY(v); DBG("\n"); formal = ao_lisp_cons(v, NULL); if (formals_tail) @@ -93,17 +103,17 @@ ao_lisp_eval(ao_lisp_poly v) formals_tail = formal; actuals = actuals->cdr; - printf("formals: "); - ao_lisp_cons_print(formals); - printf("\n"); - printf("actuals: "); - ao_lisp_cons_print(actuals); - printf("\n"); + DBG("formals: "); + DBG_CONS(formals); + DBG("\n"); + DBG("actuals: "); + DBG_CONS(actuals); + DBG("\n"); /* Process all of the arguments */ if (actuals) { v = actuals->car; - printf ("actual: "); ao_lisp_poly_print(v); printf("\n"); + DBG ("actual: "); DBG_POLY(v); DBG("\n"); break; } @@ -115,13 +125,13 @@ ao_lisp_eval(ao_lisp_poly v) v = b->func(formals->cdr); - printf ("eval: "); - ao_lisp_cons_print(formals); - printf(" -> "); - ao_lisp_poly_print(v); - printf ("\n"); + DBG ("eval: "); + DBG_CONS(formals); + DBG(" -> "); + DBG_POLY(v); + DBG ("\n"); } else { - printf ("invalid eval\n"); + DBG ("invalid eval\n"); } if (--cons) { @@ -137,11 +147,11 @@ ao_lisp_eval(ao_lisp_poly v) formals_tail = formal; stack = stack->cdr; - printf("stack pop: stack"); ao_lisp_cons_print(stack); printf("\n"); - printf("stack pop: actuals"); ao_lisp_cons_print(actuals); printf("\n"); - printf("stack pop: formals"); ao_lisp_cons_print(formals); printf("\n"); + DBG("stack pop: stack"); DBG_CONS(stack); DBG("\n"); + DBG("stack pop: actuals"); DBG_CONS(actuals); DBG("\n"); + DBG("stack pop: formals"); DBG_CONS(formals); DBG("\n"); } else { - printf("done func\n"); + DBG("done func\n"); break; } } diff --git a/src/lisp/ao_lisp_lex.c b/src/lisp/ao_lisp_lex.c index d62db872..fe7c47f4 100644 --- a/src/lisp/ao_lisp_lex.c +++ b/src/lisp/ao_lisp_lex.c @@ -14,133 +14,3 @@ #include "ao_lisp.h" -const uint32_t classTable[256] = { - IGNORE, /* ^@ */ - IGNORE, /* ^A */ - IGNORE, /* ^B */ - IGNORE, /* ^C */ - IGNORE, /* ^D */ - IGNORE, /* ^E */ - IGNORE, /* ^F */ - IGNORE, /* ^G */ - IGNORE, /* ^H */ - WHITE, /* ^I */ - WHITE, /* ^J */ - WHITE, /* ^K */ - WHITE, /* ^L */ - WHITE, /* ^M */ - IGNORE, /* ^N */ - IGNORE, /* ^O */ - IGNORE, /* ^P */ - IGNORE, /* ^Q */ - IGNORE, /* ^R */ - IGNORE, /* ^S */ - IGNORE, /* ^T */ - IGNORE, /* ^U */ - IGNORE, /* ^V */ - IGNORE, /* ^W */ - IGNORE, /* ^X */ - IGNORE, /* ^Y */ - IGNORE, /* ^Z */ - IGNORE, /* ^[ */ - IGNORE, /* ^\ */ - IGNORE, /* ^] */ - IGNORE, /* ^^ */ - IGNORE, /* ^_ */ - PRINTABLE|WHITE, /* */ - PRINTABLE, /* ! */ - PRINTABLE|STRINGC, /* " */ - PRINTABLE|COMMENT, /* # */ - PRINTABLE, /* $ */ - PRINTABLE, /* % */ - PRINTABLE, /* & */ - PRINTABLE|QUOTEC, /* ' */ - PRINTABLE|BRA, /* ( */ - PRINTABLE|KET, /* ) */ - PRINTABLE, /* * */ - PRINTABLE|SIGN, /* + */ - PRINTABLE, /* , */ - PRINTABLE|SIGN, /* - */ - PRINTABLE|DOT, /* . */ - PRINTABLE, /* / */ - PRINTABLE|DIGIT, /* 0 */ - PRINTABLE|DIGIT, /* 1 */ - PRINTABLE|DIGIT, /* 2 */ - PRINTABLE|DIGIT, /* 3 */ - PRINTABLE|DIGIT, /* 4 */ - PRINTABLE|DIGIT, /* 5 */ - PRINTABLE|DIGIT, /* 6 */ - PRINTABLE|DIGIT, /* 7 */ - PRINTABLE|DIGIT, /* 8 */ - PRINTABLE|DIGIT, /* 9 */ - PRINTABLE, /* : */ - PRINTABLE|COMMENT, /* ; */ - PRINTABLE, /* < */ - PRINTABLE, /* = */ - PRINTABLE, /* > */ - PRINTABLE, /* ? */ - PRINTABLE, /* @ */ - PRINTABLE, /* A */ - PRINTABLE, /* B */ - PRINTABLE, /* C */ - PRINTABLE, /* D */ - PRINTABLE|EXP, /* E */ - PRINTABLE, /* F */ - PRINTABLE, /* G */ - PRINTABLE, /* H */ - PRINTABLE, /* I */ - PRINTABLE, /* J */ - PRINTABLE, /* K */ - PRINTABLE, /* L */ - PRINTABLE, /* M */ - PRINTABLE, /* N */ - PRINTABLE, /* O */ - PRINTABLE, /* P */ - PRINTABLE, /* Q */ - PRINTABLE, /* R */ - PRINTABLE, /* S */ - PRINTABLE, /* T */ - PRINTABLE, /* U */ - PRINTABLE, /* V */ - PRINTABLE, /* W */ - PRINTABLE, /* X */ - PRINTABLE, /* Y */ - PRINTABLE, /* Z */ - PRINTABLE|BRA, /* [ */ - PRINTABLE|BACKSLASH, /* \ */ - PRINTABLE|KET, /* ] */ - PRINTABLE, /* ^ */ - PRINTABLE, /* _ */ - PRINTABLE, /* ` */ - PRINTABLE, /* a */ - PRINTABLE, /* b */ - PRINTABLE, /* c */ - PRINTABLE, /* d */ - PRINTABLE|EXP, /* e */ - PRINTABLE, /* f */ - PRINTABLE, /* g */ - PRINTABLE, /* h */ - PRINTABLE, /* i */ - PRINTABLE, /* j */ - PRINTABLE, /* k */ - PRINTABLE, /* l */ - PRINTABLE, /* m */ - PRINTABLE, /* n */ - PRINTABLE, /* o */ - PRINTABLE, /* p */ - PRINTABLE, /* q */ - PRINTABLE, /* r */ - PRINTABLE, /* s */ - PRINTABLE, /* t */ - PRINTABLE, /* u */ - PRINTABLE, /* v */ - PRINTABLE, /* w */ - PRINTABLE, /* x */ - PRINTABLE, /* y */ - PRINTABLE, /* z */ - PRINTABLE|BRA, /* { */ - PRINTABLE|VBAR, /* | */ - PRINTABLE|KET, /* } */ - PRINTABLE|TWIDDLE, /* ~ */ - IGNORE, /* ^? */ -}; diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index f6a108e9..d008519b 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -120,7 +120,6 @@ collect(void) { int i; - printf("collect\n"); /* Mark */ memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy)); for (i = 0; i < AO_LISP_ROOT; i++) diff --git a/src/lisp/ao_lisp_read.c b/src/lisp/ao_lisp_read.c new file mode 100644 index 00000000..ccb4ba3a --- /dev/null +++ b/src/lisp/ao_lisp_read.c @@ -0,0 +1,448 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" +#include "ao_lisp_read.h" + +static const uint16_t lex_classes[128] = { + IGNORE, /* ^@ */ + IGNORE, /* ^A */ + IGNORE, /* ^B */ + IGNORE, /* ^C */ + IGNORE, /* ^D */ + IGNORE, /* ^E */ + IGNORE, /* ^F */ + IGNORE, /* ^G */ + IGNORE, /* ^H */ + WHITE, /* ^I */ + WHITE, /* ^J */ + WHITE, /* ^K */ + WHITE, /* ^L */ + WHITE, /* ^M */ + IGNORE, /* ^N */ + IGNORE, /* ^O */ + IGNORE, /* ^P */ + IGNORE, /* ^Q */ + IGNORE, /* ^R */ + IGNORE, /* ^S */ + IGNORE, /* ^T */ + IGNORE, /* ^U */ + IGNORE, /* ^V */ + IGNORE, /* ^W */ + IGNORE, /* ^X */ + IGNORE, /* ^Y */ + IGNORE, /* ^Z */ + IGNORE, /* ^[ */ + IGNORE, /* ^\ */ + IGNORE, /* ^] */ + IGNORE, /* ^^ */ + IGNORE, /* ^_ */ + PRINTABLE|WHITE, /* */ + PRINTABLE, /* ! */ + PRINTABLE|STRINGC, /* " */ + PRINTABLE|COMMENT, /* # */ + PRINTABLE, /* $ */ + PRINTABLE, /* % */ + PRINTABLE, /* & */ + PRINTABLE|QUOTEC, /* ' */ + PRINTABLE|BRA, /* ( */ + PRINTABLE|KET, /* ) */ + PRINTABLE, /* * */ + PRINTABLE|SIGN, /* + */ + PRINTABLE, /* , */ + PRINTABLE|SIGN, /* - */ + PRINTABLE, /* . */ + PRINTABLE, /* / */ + PRINTABLE|DIGIT, /* 0 */ + PRINTABLE|DIGIT, /* 1 */ + PRINTABLE|DIGIT, /* 2 */ + PRINTABLE|DIGIT, /* 3 */ + PRINTABLE|DIGIT, /* 4 */ + PRINTABLE|DIGIT, /* 5 */ + PRINTABLE|DIGIT, /* 6 */ + PRINTABLE|DIGIT, /* 7 */ + PRINTABLE|DIGIT, /* 8 */ + PRINTABLE|DIGIT, /* 9 */ + PRINTABLE, /* : */ + PRINTABLE|COMMENT, /* ; */ + PRINTABLE, /* < */ + PRINTABLE, /* = */ + PRINTABLE, /* > */ + PRINTABLE, /* ? */ + PRINTABLE, /* @ */ + PRINTABLE, /* A */ + PRINTABLE, /* B */ + PRINTABLE, /* C */ + PRINTABLE, /* D */ + PRINTABLE, /* E */ + PRINTABLE, /* F */ + PRINTABLE, /* G */ + PRINTABLE, /* H */ + PRINTABLE, /* I */ + PRINTABLE, /* J */ + PRINTABLE, /* K */ + PRINTABLE, /* L */ + PRINTABLE, /* M */ + PRINTABLE, /* N */ + PRINTABLE, /* O */ + PRINTABLE, /* P */ + PRINTABLE, /* Q */ + PRINTABLE, /* R */ + PRINTABLE, /* S */ + PRINTABLE, /* T */ + PRINTABLE, /* U */ + PRINTABLE, /* V */ + PRINTABLE, /* W */ + PRINTABLE, /* X */ + PRINTABLE, /* Y */ + PRINTABLE, /* Z */ + PRINTABLE, /* [ */ + PRINTABLE|BACKSLASH, /* \ */ + PRINTABLE, /* ] */ + PRINTABLE, /* ^ */ + PRINTABLE, /* _ */ + PRINTABLE, /* ` */ + PRINTABLE, /* a */ + PRINTABLE, /* b */ + PRINTABLE, /* c */ + PRINTABLE, /* d */ + PRINTABLE, /* e */ + PRINTABLE, /* f */ + PRINTABLE, /* g */ + PRINTABLE, /* h */ + PRINTABLE, /* i */ + PRINTABLE, /* j */ + PRINTABLE, /* k */ + PRINTABLE, /* l */ + PRINTABLE, /* m */ + PRINTABLE, /* n */ + PRINTABLE, /* o */ + PRINTABLE, /* p */ + PRINTABLE, /* q */ + PRINTABLE, /* r */ + PRINTABLE, /* s */ + PRINTABLE, /* t */ + PRINTABLE, /* u */ + PRINTABLE, /* v */ + PRINTABLE, /* w */ + PRINTABLE, /* x */ + PRINTABLE, /* y */ + PRINTABLE, /* z */ + PRINTABLE, /* { */ + PRINTABLE|VBAR, /* | */ + PRINTABLE, /* } */ + PRINTABLE|TWIDDLE, /* ~ */ + IGNORE, /* ^? */ +}; + +static int lex_unget_c; + +static inline int +lex_get() +{ + int c; + if (lex_unget_c) { + c = lex_unget_c; + lex_unget_c = 0; + } else + c = getchar(); + return c; +} + +static inline void +lex_unget(int c) +{ + if (c != EOF) + lex_unget_c = c; +} + +static int +lex_quoted (void) +{ + int c; + int v; + int count; + + c = lex_get(); +// if (jumping) +// return nil; + if (c == EOF) + return EOF; + c &= 0x7f; + switch (c) { + case 'n': + return '\n'; + case 'f': + return '\f'; + case 'b': + return '\b'; + case 'r': + return '\r'; + case 'v': + return '\v'; + case 't': + return '\t'; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + v = c - '0'; + count = 1; + while (count <= 3) { + c = lex_get(); +// if (jumping) +// return nil; + if (c == EOF) + return EOF; + c &= 0x7f; + if (c < '0' || '7' < c) { + lex_unget(c); + break; + } + v = (v << 3) + c - '0'; + ++count; + } + return v; + default: + return c; + } +} + +static uint16_t lex_class; + +static int +lexc(void) +{ + int c; + do { + c = lex_get(); + if (c == EOF) { + lex_class = ENDOFFILE; + c = 0; + } else { + c &= 0x7f; + lex_class = lex_classes[c]; + if (lex_class & BACKSLASH) { + c = lex_quoted(); + if (c == EOF) + lex_class = ENDOFFILE; + else + lex_class = PRINTABLE; + } + } + } while (lex_class & IGNORE); + return c; +} + +#define AO_LISP_TOKEN_MAX 32 + +static char token_string[AO_LISP_TOKEN_MAX]; +static int token_int; +static int token_len; + +static inline void add_token(int c) { + if (c && token_len < AO_LISP_TOKEN_MAX - 1) + token_string[token_len++] = c; +} + +static inline void end_token(void) { + token_string[token_len] = '\0'; +} + +static int +lex(void) +{ + int c; + + token_len = 0; + for (;;) { + c = lexc(); + if (lex_class & ENDOFFILE) + return AO_LISP_NIL; + +// if (jumping) +// return nil; + if (lex_class & WHITE) + continue; + + if (lex_class & (BRA|KET|QUOTEC)) { + add_token(c); + end_token(); + switch (c) { + case '(': + return OPEN; + case ')': + return CLOSE; + case '\'': + return QUOTE; + } + } + if (lex_class & TWIDDLE) { + token_int = lexc(); + return NUM; + } + if (lex_class & STRINGC) { + for (;;) { + c = lexc(); +// if (jumping) +// return nil; + if (lex_class & (STRINGC|ENDOFFILE)) { + end_token(); + return STRING; + } + add_token(c); + } + } + if (lex_class & PRINTABLE) { + int isnum; + int hasdigit; + int isneg; + + isnum = 1; + hasdigit = 0; + token_int = 0; + isneg = 0; + for (;;) { + if (!(lex_class & NUMBER)) { + isnum = 0; + } else { + if (token_len != 0 && + (lex_class & SIGN)) + { + isnum = 0; + } + if (c == '-') + isneg = 1; + if (lex_class & DIGIT) { + hasdigit = 1; + if (isnum) + token_int = token_int * 10 + c - '0'; + } + } + add_token (c); + c = lexc (); +// if (jumping) +// return nil; + if (lex_class & (NOTNAME)) { +// if (lex_class & ENDOFFILE) +// clearerr (f); + lex_unget(c); + end_token (); + if (isnum && hasdigit) { + if (isneg) + token_int = -token_int; + return NUM; + } + return NAME; + } + } + + } + } +} + +static int parse_token; +static uint8_t been_here; +static struct ao_lisp_cons *read_cons; +static struct ao_lisp_cons *read_cons_tail; +static struct ao_lisp_cons *read_stack; + +static ao_lisp_poly +read_item(void) +{ + struct ao_lisp_atom *atom; + char *string; + int cons; + ao_lisp_poly v; + + if (!been_here) { + ao_lisp_root_add(&ao_lisp_cons_type, &read_cons); + ao_lisp_root_add(&ao_lisp_cons_type, &read_cons_tail); + ao_lisp_root_add(&ao_lisp_cons_type, &read_stack); + } + + cons = 0; + read_cons = read_cons_tail = read_stack = 0; + for (;;) { + while (parse_token == OPEN) { + if (cons++) + read_stack = ao_lisp_cons(ao_lisp_cons_poly(read_cons), read_stack); + read_cons = NULL; + read_cons_tail = NULL; + parse_token = lex(); + } + + switch (parse_token) { + case ENDOFFILE: + default: + v = AO_LISP_NIL; + break; + case NAME: + atom = ao_lisp_atom_intern(token_string); + if (atom) + v = ao_lisp_atom_poly(atom); + else + v = AO_LISP_NIL; + break; + case NUM: + v = ao_lisp_int_poly(token_int); + break; + case STRING: + string = ao_lisp_string_copy(token_string); + if (string) + v = ao_lisp_string_poly(string); + else + v = AO_LISP_NIL; + break; + case CLOSE: + if (cons) + v = ao_lisp_cons_poly(read_cons); + else + v = AO_LISP_NIL; + if (--cons) { + read_cons = ao_lisp_poly_cons(read_stack->car); + read_stack = read_stack->cdr; + for (read_cons_tail = read_cons; + read_cons_tail && read_cons_tail->cdr; + read_cons_tail = read_cons_tail->cdr) + ; + } + break; + } + + if (!cons) + break; + + struct ao_lisp_cons *read = ao_lisp_cons(v, NULL); + if (read_cons_tail) + read_cons_tail->cdr = read; + else + read_cons = read; + read_cons_tail = read; + + parse_token = lex(); + } + return v; +} + +ao_lisp_poly +ao_lisp_read(void) +{ + parse_token = lex(); + return read_item(); +} diff --git a/src/lisp/ao_lisp_read.h b/src/lisp/ao_lisp_read.h new file mode 100644 index 00000000..1c994d56 --- /dev/null +++ b/src/lisp/ao_lisp_read.h @@ -0,0 +1,49 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _AO_LISP_READ_H_ +#define _AO_LISP_READ_H_ + +# define END 0 +# define NAME 1 +# define OPEN 2 +# define CLOSE 3 +# define QUOTE 4 +# define STRING 5 +# define NUM 6 + +/* + * character classes + */ + +# define PRINTABLE 0x00000001 /* \t \n ' ' - '~' */ +# define QUOTED 0x00000002 /* \ anything */ +# define BRA 0x00000004 /* ( [ { */ +# define KET 0x00000008 /* ) ] } */ +# define WHITE 0x00000010 /* ' ' \t \n */ +# define DIGIT 0x00000020 /* [0-9] */ +# define SIGN 0x00000040 /* +- */ +# define ENDOFFILE 0x00000080 /* end of file */ +# define COMMENT 0x00000100 /* ; # */ +# define IGNORE 0x00000200 /* \0 - ' ' */ +# define QUOTEC 0x00000400 /* ' */ +# define BACKSLASH 0x00000800 /* \ */ +# define VBAR 0x00001000 /* | */ +# define TWIDDLE 0x00002000 /* ~ */ +# define STRINGC 0x00004000 /* " */ + +# define NOTNAME (STRINGC|TWIDDLE|VBAR|QUOTEC|COMMENT|ENDOFFILE|WHITE|KET|BRA) +# define NUMBER (DIGIT|SIGN) + +#endif /* _AO_LISP_READ_H_ */ diff --git a/src/lisp/ao_lisp_string.c b/src/lisp/ao_lisp_string.c index 87024271..1ab56933 100644 --- a/src/lisp/ao_lisp_string.c +++ b/src/lisp/ao_lisp_string.c @@ -43,6 +43,18 @@ ao_lisp_string_new(int len) { return a; } +char * +ao_lisp_string_copy(char *a) +{ + int alen = strlen(a); + + char *r = ao_lisp_alloc(alen + 1); + if (!r) + return NULL; + strcpy(r, a); + return r; +} + char * ao_lisp_string_cat(char *a, char *b) { diff --git a/src/test/Makefile b/src/test/Makefile index a409ae13..e841bfde 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -89,7 +89,7 @@ ao_quaternion_test: ao_quaternion_test.c ao_quaternion.h cc $(CFLAGS) -o $@ ao_quaternion_test.c -lm -AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o ao_lisp_lex.o ao_lisp_cons.o ao_lisp_string.o ao_lisp_atom.o ao_lisp_int.o ao_lisp_prim.o ao_lisp_eval.o ao_lisp_poly.o ao_lisp_builtin.o +AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o ao_lisp_lex.o ao_lisp_cons.o ao_lisp_string.o ao_lisp_atom.o ao_lisp_int.o ao_lisp_prim.o ao_lisp_eval.o ao_lisp_poly.o ao_lisp_builtin.o ao_lisp_read.o ao_lisp_test: $(AO_LISP_OBJS) cc $(CFLAGS) -o $@ $(AO_LISP_OBJS) diff --git a/src/test/ao_lisp_test.c b/src/test/ao_lisp_test.c index bbadfa75..96f1fd72 100644 --- a/src/test/ao_lisp_test.c +++ b/src/test/ao_lisp_test.c @@ -23,6 +23,7 @@ main (int argc, char **argv) { int i, j; struct ao_lisp_atom *atom; + ao_lisp_poly poly; ao_lisp_root_add(&ao_lisp_cons_type, (void **) &list); ao_lisp_root_add(&ao_lisp_string_type, (void **) &string); @@ -55,4 +56,12 @@ main (int argc, char **argv) printf ("\n"); ao_lisp_poly_print(ao_lisp_eval(ao_lisp_cons_poly(list))); printf ("\n"); + + while ((poly = ao_lisp_read())) { + poly = ao_lisp_eval(poly); + ao_lisp_poly_print(poly); + putchar ('\n'); + fflush(stdout); + } + } -- cgit v1.2.3 From d2408e72d1e0d3459918601712b09860ab17e200 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 1 Nov 2016 21:14:45 -0700 Subject: altos/lisp: Change lisp objects to use ao_poly everywhere. Add const This makes all lisp objects use 16-bit ints for references so we can hold more stuff in small amounts of memory. Also adds a separate constant pool of lisp objects for builtins, initial atoms and constant lisp code. Now builds (and runs!) on the nucleo-32 boards. Signed-off-by: Keith Packard --- src/lisp/.gitignore | 2 + src/lisp/Makefile | 32 +++++ src/lisp/ao_lisp.h | 238 ++++++++++++++++++++++----------- src/lisp/ao_lisp_atom.c | 43 +++--- src/lisp/ao_lisp_builtin.c | 189 +++++++++++++++++++++++++- src/lisp/ao_lisp_cons.c | 19 +-- src/lisp/ao_lisp_const.lisp | 1 + src/lisp/ao_lisp_eval.c | 57 ++++++-- src/lisp/ao_lisp_int.c | 3 +- src/lisp/ao_lisp_make_const.c | 90 +++++++++++++ src/lisp/ao_lisp_mem.c | 41 ++++-- src/lisp/ao_lisp_poly.c | 89 +----------- src/lisp/ao_lisp_prim.c | 40 +++--- src/lisp/ao_lisp_read.c | 31 +++-- src/lisp/ao_lisp_rep.c | 40 ++++++ src/lisp/ao_lisp_string.c | 6 +- src/nucleao-32/.gitignore | 2 + src/nucleao-32/Makefile | 11 ++ src/nucleao-32/ao_nucleo.c | 7 + src/nucleao-32/flash-loader/.gitignore | 2 + src/test/Makefile | 8 +- src/test/ao_lisp_test.c | 40 +++--- 22 files changed, 714 insertions(+), 277 deletions(-) create mode 100644 src/lisp/.gitignore create mode 100644 src/lisp/Makefile create mode 100644 src/lisp/ao_lisp_const.lisp create mode 100644 src/lisp/ao_lisp_make_const.c create mode 100644 src/lisp/ao_lisp_rep.c create mode 100644 src/nucleao-32/.gitignore create mode 100644 src/nucleao-32/flash-loader/.gitignore (limited to 'src') diff --git a/src/lisp/.gitignore b/src/lisp/.gitignore new file mode 100644 index 00000000..76a555ea --- /dev/null +++ b/src/lisp/.gitignore @@ -0,0 +1,2 @@ +ao_lisp_make_const +ao_lisp_const.h diff --git a/src/lisp/Makefile b/src/lisp/Makefile new file mode 100644 index 00000000..e8c3c02c --- /dev/null +++ b/src/lisp/Makefile @@ -0,0 +1,32 @@ +all: ao_lisp_const.h + +clean: + rm -f ao_lisp_const.h $(OBJS) ao_lisp_make_const + +ao_lisp_const.h: ao_lisp_const.lisp ao_lisp_make_const + ./ao_lisp_make_const < ao_lisp_const.lisp > $@ + +SRCS=\ + ao_lisp_make_const.c\ + ao_lisp_mem.c \ + ao_lisp_cons.c \ + ao_lisp_string.c \ + ao_lisp_atom.c \ + ao_lisp_int.c \ + ao_lisp_poly.c \ + ao_lisp_prim.c \ + ao_lisp_builtin.c \ + ao_lisp_read.c + +OBJS=$(SRCS:.c=.o) + +CFLAGS=-DAO_LISP_MAKE_CONST -O0 -g + +HDRS=\ + ao_lisp.h \ + ao_lisp_read.h + +ao_lisp_make_const: $(OBJS) + $(CC) $(CFLAGS) -o $@ $(OBJS) + +$(OBJS): $(HDRS) diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 6667dcc2..4fac861b 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -15,78 +15,158 @@ #ifndef _AO_LISP_H_ #define _AO_LISP_H_ +#if !defined(AO_LISP_TEST) && !defined(AO_LISP_MAKE_CONST) +#include +#define AO_LISP_ALTOS 1 +#endif + #include #include #include +#ifdef AO_LISP_MAKE_CONST +#define AO_LISP_POOL_CONST 16384 +extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST]; +#else +#include "ao_lisp_const.h" +#endif + +/* Primitive types */ +#define AO_LISP_CONS 0 +#define AO_LISP_INT 1 +#define AO_LISP_STRING 2 +#define AO_LISP_OTHER 3 -# define AO_LISP_CONS 0 -# define AO_LISP_INT 1 -# define AO_LISP_STRING 2 -# define AO_LISP_OTHER 3 +#define AO_LISP_TYPE_MASK 0x0003 +#define AO_LISP_TYPE_SHIFT 2 +#define AO_LISP_REF_MASK 0x7ffc +#define AO_LISP_CONST 0x8000 -# define AO_LISP_ATOM 4 -# define AO_LISP_BUILTIN 5 +/* These have a type value at the start of the struct */ +#define AO_LISP_ATOM 4 +#define AO_LISP_BUILTIN 5 +#define AO_LISP_NUM_TYPE 6 -# define AO_LISP_NIL 0 +#define AO_LISP_NIL 0 #define AO_LISP_POOL 1024 -#define AO_LISP_ROOT 16 -static inline void *ao_lisp_set_ref(void *addr) { - return (void *) ((intptr_t)addr | 1); +extern uint8_t ao_lisp_pool[AO_LISP_POOL]; +extern uint16_t ao_lisp_top; + +#define AO_LISP_OOM 0x01 +#define AO_LISP_DIVIDE_BY_ZERO 0x02 +#define AO_LISP_INVALID 0x04 + +extern uint8_t ao_lisp_exception; + +typedef uint16_t ao_poly; + +static inline void * +ao_lisp_ref(ao_poly poly) { + if (poly == AO_LISP_NIL) + return NULL; + if (poly & AO_LISP_CONST) + return (void *) ((ao_lisp_const - 4) + (poly & AO_LISP_REF_MASK)); + else + return (void *) ((ao_lisp_pool - 4) + (poly & AO_LISP_REF_MASK)); } -static inline void *ao_lisp_clear_ref(void *addr) { - return (void *) ((intptr_t)addr & ~1); +static inline ao_poly +ao_lisp_poly(const void *addr, ao_poly type) { + const uint8_t *a = addr; + if (addr == NULL) + return AO_LISP_NIL; + if (ao_lisp_pool <= a && a < ao_lisp_pool + AO_LISP_POOL) + return (a - (ao_lisp_pool - 4)) | type; + else if (ao_lisp_const <= a && a <= ao_lisp_const + AO_LISP_POOL_CONST) + return AO_LISP_CONST | (a - (ao_lisp_const - 4)) | type; + else { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } } -extern uint8_t ao_lisp_pool[AO_LISP_POOL]; +#define AO_LISP_POLY(addr, type) (((ao_lisp_pool <= ((uint8_t *) (a)) && \ + ((uint8_t *) (a)) < ao_lisp_pool + AO_LISP_POOL) ? \ + ((uint8_t *) (a) - (ao_lisp_pool - 4)) : \ + (((uint8_t *) (a) - (ao_lisp_const - 4)) | AO_LISP_POOL_CONST)) | \ + (type)) -struct ao_lisp_mem_type { +struct ao_lisp_type { void (*mark)(void *addr); int (*size)(void *addr); void (*move)(void *addr); }; -typedef intptr_t ao_lisp_poly; - struct ao_lisp_cons { - ao_lisp_poly car; - struct ao_lisp_cons *cdr; + ao_poly car; + ao_poly cdr; }; struct ao_lisp_atom { - uint8_t type; - ao_lisp_poly val; - struct ao_lisp_atom *next; - char name[]; + uint8_t type; + uint8_t pad[1]; + ao_poly val; + ao_poly next; + char name[]; }; -#define AO_LISP_ATOM_CONST ((struct ao_lisp_atom *) (intptr_t) 1) - -extern const struct ao_lisp_atom *ao_lisp_builtins[]; +#define AO_LISP_LAMBDA 0 +#define AO_LISP_NLAMBDA 1 +#define AO_LISP_MACRO 2 +#define AO_LISP_LEXPR 3 struct ao_lisp_builtin { - uint8_t type; - ao_lisp_poly (*func)(struct ao_lisp_cons *cons); - char name[]; + uint8_t type; + uint8_t args; + uint16_t func; }; +enum ao_lisp_builtin_id { + builtin_car, + builtin_cdr, + builtin_cons, + builtin_quote, + builtin_print, + builtin_plus, + builtin_minus, + builtin_times, + builtin_divide, + builtin_mod, + builtin_last +}; + +typedef ao_poly (*ao_lisp_func_t)(struct ao_lisp_cons *cons); + +extern ao_lisp_func_t ao_lisp_builtins[]; + +static inline ao_lisp_func_t +ao_lisp_func(struct ao_lisp_builtin *b) +{ + return ao_lisp_builtins[b->func]; +} + static inline void * -ao_lisp_poly_other(ao_lisp_poly poly) { - return (void *) (poly - AO_LISP_OTHER); +ao_lisp_poly_other(ao_poly poly) { + return ao_lisp_ref(poly); } -static const inline ao_lisp_poly +static inline ao_poly ao_lisp_other_poly(const void *other) { - return (ao_lisp_poly) other + AO_LISP_OTHER; + return ao_lisp_poly(other, AO_LISP_OTHER); +} + +static inline int +ao_lisp_mem_round(int size) +{ + return (size + 3) & ~3; } -#define AO_LISP_OTHER_POLY(other) ((ao_lisp_poly)(other) + AO_LISP_OTHER) +#define AO_LISP_OTHER_POLY(other) ((ao_poly)(other) + AO_LISP_OTHER) -static inline int ao_lisp_poly_type(ao_lisp_poly poly) { +static inline int ao_lisp_poly_type(ao_poly poly) { int type = poly & 3; if (type == AO_LISP_OTHER) return *((uint8_t *) ao_lisp_poly_other(poly)); @@ -94,75 +174,75 @@ static inline int ao_lisp_poly_type(ao_lisp_poly poly) { } static inline struct ao_lisp_cons * -ao_lisp_poly_cons(ao_lisp_poly poly) +ao_lisp_poly_cons(ao_poly poly) { - return (struct ao_lisp_cons *) (poly - AO_LISP_CONS); + return ao_lisp_ref(poly); } -static inline ao_lisp_poly +static inline ao_poly ao_lisp_cons_poly(struct ao_lisp_cons *cons) { - return (ao_lisp_poly) cons + AO_LISP_CONS; + return ao_lisp_poly(cons, AO_LISP_CONS); } static inline int -ao_lisp_poly_int(ao_lisp_poly poly) +ao_lisp_poly_int(ao_poly poly) { - return (int) (poly >> 2); + return (int) poly >> AO_LISP_TYPE_SHIFT; } -static inline ao_lisp_poly +static inline ao_poly ao_lisp_int_poly(int i) { - return ((ao_lisp_poly) i << 2) + AO_LISP_INT; + return ((ao_poly) i << 2) + AO_LISP_INT; } static inline char * -ao_lisp_poly_string(ao_lisp_poly poly) +ao_lisp_poly_string(ao_poly poly) { - return (char *) (poly - AO_LISP_STRING); + return ao_lisp_ref(poly); } -static inline ao_lisp_poly -ao_lisp_string_poly(char *s) { - return (ao_lisp_poly) s + AO_LISP_STRING; +static inline ao_poly +ao_lisp_string_poly(char *s) +{ + return ao_lisp_poly(s, AO_LISP_STRING); } static inline struct ao_lisp_atom * -ao_lisp_poly_atom(ao_lisp_poly poly) +ao_lisp_poly_atom(ao_poly poly) { - return (struct ao_lisp_atom *) (poly - AO_LISP_OTHER); + return ao_lisp_ref(poly); } -static inline ao_lisp_poly +static inline ao_poly ao_lisp_atom_poly(struct ao_lisp_atom *a) { - return (ao_lisp_poly) a + AO_LISP_OTHER; + return ao_lisp_poly(a, AO_LISP_OTHER); } static inline struct ao_lisp_builtin * -ao_lisp_poly_builtin(ao_lisp_poly poly) +ao_lisp_poly_builtin(ao_poly poly) { - return (struct ao_lisp_builtin *) (poly - AO_LISP_OTHER); + return ao_lisp_ref(poly); } -static inline ao_lisp_poly +static inline ao_poly ao_lisp_builtin_poly(struct ao_lisp_builtin *b) { - return (ao_lisp_poly) b + AO_LISP_OTHER; + return ao_lisp_poly(b, AO_LISP_OTHER); } /* memory functions */ - void -ao_lisp_mark(const struct ao_lisp_mem_type *type, void *addr); +ao_lisp_mark(const struct ao_lisp_type *type, void *addr); /* returns 1 if the object was already marked */ int ao_lisp_mark_memory(void *addr, int size); void * -ao_lisp_move(const struct ao_lisp_mem_type *type, void *addr); +ao_lisp_move(const struct ao_lisp_type *type, void *addr); /* returns NULL if the object was already moved */ void * @@ -172,22 +252,22 @@ void * ao_lisp_alloc(int size); int -ao_lisp_root_add(const struct ao_lisp_mem_type *type, void *addr); +ao_lisp_root_add(const struct ao_lisp_type *type, void *addr); void ao_lisp_root_clear(void *addr); /* cons */ -extern const struct ao_lisp_mem_type ao_lisp_cons_type; +extern const struct ao_lisp_type ao_lisp_cons_type; struct ao_lisp_cons * -ao_lisp_cons(ao_lisp_poly car, struct ao_lisp_cons *cdr); +ao_lisp_cons_cons(ao_poly car, struct ao_lisp_cons *cdr); void -ao_lisp_cons_print(struct ao_lisp_cons *cons); +ao_lisp_cons_print(ao_poly); /* string */ -extern const struct ao_lisp_mem_type ao_lisp_string_type; +extern const struct ao_lisp_type ao_lisp_string_type; char * ao_lisp_string_new(int len); @@ -199,44 +279,50 @@ char * ao_lisp_string_cat(char *a, char *b); void -ao_lisp_string_print(char *s); +ao_lisp_string_print(ao_poly s); /* atom */ -extern const struct ao_lisp_mem_type ao_lisp_atom_type; +extern const struct ao_lisp_type ao_lisp_atom_type; + +extern struct ao_lisp_atom *ao_lisp_atoms; void ao_lisp_atom_init(void); void -ao_lisp_atom_print(struct ao_lisp_atom *atom); +ao_lisp_atom_print(ao_poly a); struct ao_lisp_atom * ao_lisp_atom_intern(char *name); /* int */ void -ao_lisp_int_print(int i); +ao_lisp_int_print(ao_poly i); /* prim */ -ao_lisp_poly -ao_lisp_poly_print(ao_lisp_poly p); +ao_poly +ao_lisp_poly_print(ao_poly p); void -ao_lisp_poly_mark(ao_lisp_poly p); +ao_lisp_poly_mark(ao_poly p); -ao_lisp_poly -ao_lisp_poly_move(ao_lisp_poly p); +ao_poly +ao_lisp_poly_move(ao_poly p); /* eval */ -ao_lisp_poly -ao_lisp_eval(ao_lisp_poly p); +ao_poly +ao_lisp_eval(ao_poly p); /* builtin */ void -ao_lisp_builtin_print(struct ao_lisp_builtin *b); +ao_lisp_builtin_print(ao_poly b); /* read */ -ao_lisp_poly +ao_poly ao_lisp_read(void); +/* rep */ +ao_poly +ao_lisp_read_eval_print(void); + #endif /* _AO_LISP_H_ */ diff --git a/src/lisp/ao_lisp_atom.c b/src/lisp/ao_lisp_atom.c index 65282142..aaa84b8d 100644 --- a/src/lisp/ao_lisp_atom.c +++ b/src/lisp/ao_lisp_atom.c @@ -34,12 +34,9 @@ static void atom_mark(void *addr) { struct ao_lisp_atom *atom = addr; - if (atom->next == AO_LISP_ATOM_CONST) - return; - for (;;) { ao_lisp_poly_mark(atom->val); - atom = atom->next; + atom = ao_lisp_poly_atom(atom->next); if (!atom) break; if (ao_lisp_mark_memory(atom, atom_size(atom))) @@ -51,49 +48,50 @@ static void atom_move(void *addr) { struct ao_lisp_atom *atom = addr; - if (atom->next == AO_LISP_ATOM_CONST) - return; - for (;;) { struct ao_lisp_atom *next; atom->val = ao_lisp_poly_move(atom->val); - next = ao_lisp_move_memory(atom->next, atom_size(atom->next)); + next = ao_lisp_poly_atom(atom->next); + next = ao_lisp_move_memory(next, atom_size(next)); if (!next) break; - atom->next = next; + atom->next = ao_lisp_atom_poly(next); atom = next; } } -const struct ao_lisp_mem_type ao_lisp_atom_type = { +const struct ao_lisp_type ao_lisp_atom_type = { .mark = atom_mark, .size = atom_size, .move = atom_move, }; -struct ao_lisp_atom *atoms; +struct ao_lisp_atom *ao_lisp_atoms; struct ao_lisp_atom * ao_lisp_atom_intern(char *name) { struct ao_lisp_atom *atom; - int b; +// int b; - for (atom = atoms; atom; atom = atom->next) { + for (atom = ao_lisp_atoms; atom; atom = ao_lisp_poly_atom(atom->next)) { + if (!strcmp(atom->name, name)) + return atom; + } +#ifdef ao_builtin_atoms + for (atom = ao_lisp_poly_atom(ao_builtin_atoms); atom; atom = ao_lisp_poly_atom(atom->next)) { if (!strcmp(atom->name, name)) return atom; } - for (b = 0; ao_lisp_builtins[b]; b++) - if (!strcmp(ao_lisp_builtins[b]->name, name)) - return (struct ao_lisp_atom *) ao_lisp_builtins[b]; - if (!atoms) - ao_lisp_root_add(&ao_lisp_atom_type, (void **) &atoms); +#endif + if (!ao_lisp_atoms) + ao_lisp_root_add(&ao_lisp_atom_type, (void **) &ao_lisp_atoms); atom = ao_lisp_alloc(name_size(name)); if (atom) { atom->type = AO_LISP_ATOM; - atom->next = atoms; - atoms = atom; + atom->next = ao_lisp_atom_poly(ao_lisp_atoms); + ao_lisp_atoms = atom; strcpy(atom->name, name); atom->val = AO_LISP_NIL; } @@ -101,7 +99,8 @@ ao_lisp_atom_intern(char *name) } void -ao_lisp_atom_print(struct ao_lisp_atom *a) +ao_lisp_atom_print(ao_poly a) { - fputs(a->name, stdout); + struct ao_lisp_atom *atom = ao_lisp_poly_atom(a); + printf("%s", atom->name); } diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index 3752a2c8..e6d55797 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -15,7 +15,192 @@ #include "ao_lisp.h" void -ao_lisp_builtin_print(struct ao_lisp_builtin *b) +ao_lisp_builtin_print(ao_poly b) { - printf("[builtin %s]", b->name); + (void) b; + printf("[builtin]"); } + +enum math_op { math_plus, math_minus, math_times, math_divide, math_mod }; + +ao_poly +ao_lisp_car(struct ao_lisp_cons *cons) +{ + if (!cons) { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + if (!cons->car) { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + if (ao_lisp_poly_type(cons->car) != AO_LISP_CONS) { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + return ao_lisp_poly_cons(cons->car)->car; +} + +ao_poly +ao_lisp_cdr(struct ao_lisp_cons *cons) +{ + if (!cons) { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + if (!cons->car) { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + if (ao_lisp_poly_type(cons->car) != AO_LISP_CONS) { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + return ao_lisp_poly_cons(cons->car)->cdr; +} + +ao_poly +ao_lisp_cons(struct ao_lisp_cons *cons) +{ + ao_poly car, cdr; + if (!cons) { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + car = cons->car; + cdr = cons->cdr; + if (!car || !cdr) { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + cdr = ao_lisp_poly_cons(cdr)->car; + if (ao_lisp_poly_type(cdr) != AO_LISP_CONS) { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + return ao_lisp_cons_poly(ao_lisp_cons_cons(car, ao_lisp_poly_cons(cdr))); +} + +ao_poly +ao_lisp_quote(struct ao_lisp_cons *cons) +{ + if (!cons) { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + return cons->car; +} + +ao_poly +ao_lisp_print(struct ao_lisp_cons *cons) +{ + ao_poly val = AO_LISP_NIL; + while (cons) { + val = cons->car; + ao_lisp_poly_print(val); + cons = ao_lisp_poly_cons(cons->cdr); + } + return val; +} + +ao_poly +ao_lisp_math(struct ao_lisp_cons *cons, enum math_op op) +{ + ao_poly ret = AO_LISP_NIL; + + while (cons) { + ao_poly car = cons->car; + uint8_t rt = ao_lisp_poly_type(ret); + uint8_t ct = ao_lisp_poly_type(car); + + cons = ao_lisp_poly_cons(cons->cdr); + + if (rt == AO_LISP_NIL) + ret = car; + + else if (rt == AO_LISP_INT && ct == AO_LISP_INT) { + int r = ao_lisp_poly_int(ret); + int c = ao_lisp_poly_int(car); + + switch(op) { + case math_plus: + r += c; + break; + case math_minus: + r -= c; + break; + case math_times: + r *= c; + break; + case math_divide: + if (c == 0) { + ao_lisp_exception |= AO_LISP_DIVIDE_BY_ZERO; + return AO_LISP_NIL; + } + r /= c; + break; + case math_mod: + if (c == 0) { + ao_lisp_exception |= AO_LISP_DIVIDE_BY_ZERO; + return AO_LISP_NIL; + } + r %= c; + break; + } + ret = ao_lisp_int_poly(r); + } + + else if (rt == AO_LISP_STRING && ct == AO_LISP_STRING && op == math_plus) + ret = ao_lisp_string_poly(ao_lisp_string_cat(ao_lisp_poly_string(ret), + ao_lisp_poly_string(car))); + else { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + } + return ret; +} + +ao_poly +ao_lisp_plus(struct ao_lisp_cons *cons) +{ + return ao_lisp_math(cons, math_plus); +} + +ao_poly +ao_lisp_minus(struct ao_lisp_cons *cons) +{ + return ao_lisp_math(cons, math_minus); +} + +ao_poly +ao_lisp_times(struct ao_lisp_cons *cons) +{ + return ao_lisp_math(cons, math_times); +} + +ao_poly +ao_lisp_divide(struct ao_lisp_cons *cons) +{ + return ao_lisp_math(cons, math_divide); +} + +ao_poly +ao_lisp_mod(struct ao_lisp_cons *cons) +{ + return ao_lisp_math(cons, math_mod); +} + +ao_lisp_func_t ao_lisp_builtins[] = { + [builtin_car] = ao_lisp_car, + [builtin_cdr] = ao_lisp_cdr, + [builtin_cons] = ao_lisp_cons, + [builtin_quote] = ao_lisp_quote, + [builtin_print] = ao_lisp_print, + [builtin_plus] = ao_lisp_plus, + [builtin_minus] = ao_lisp_minus, + [builtin_times] = ao_lisp_times, + [builtin_divide] = ao_lisp_divide, + [builtin_mod] = ao_lisp_mod +}; + diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c index 60cbb2f3..65908e30 100644 --- a/src/lisp/ao_lisp_cons.c +++ b/src/lisp/ao_lisp_cons.c @@ -20,7 +20,7 @@ static void cons_mark(void *addr) for (;;) { ao_lisp_poly_mark(cons->car); - cons = cons->cdr; + cons = ao_lisp_poly_cons(cons->cdr); if (!cons) break; if (ao_lisp_mark_memory(cons, sizeof (struct ao_lisp_cons))) @@ -42,42 +42,43 @@ static void cons_move(void *addr) struct ao_lisp_cons *cdr; cons->car = ao_lisp_poly_move(cons->car); - cdr = ao_lisp_move_memory(cons->cdr, sizeof (struct ao_lisp_cons)); + cdr = ao_lisp_poly_cons(cons->cdr); + cdr = ao_lisp_move_memory(cdr, sizeof (struct ao_lisp_cons)); if (!cdr) break; - cons->cdr = cdr; + cons->cdr = ao_lisp_cons_poly(cdr); cons = cdr; } } -const struct ao_lisp_mem_type ao_lisp_cons_type = { +const struct ao_lisp_type ao_lisp_cons_type = { .mark = cons_mark, .size = cons_size, .move = cons_move, }; struct ao_lisp_cons * -ao_lisp_cons(ao_lisp_poly car, struct ao_lisp_cons *cdr) +ao_lisp_cons_cons(ao_poly car, struct ao_lisp_cons *cdr) { struct ao_lisp_cons *cons = ao_lisp_alloc(sizeof (struct ao_lisp_cons)); if (!cons) return NULL; cons->car = car; - cons->cdr = cdr; + cons->cdr = ao_lisp_cons_poly(cdr); return cons; } void -ao_lisp_cons_print(struct ao_lisp_cons *cons) +ao_lisp_cons_print(ao_poly c) { + struct ao_lisp_cons *cons = ao_lisp_poly_cons(c); int first = 1; printf("("); while (cons) { if (!first) printf(" "); - fflush(stdout); ao_lisp_poly_print(cons->car); - cons = cons->cdr; + cons = ao_lisp_poly_cons(cons->cdr); first = 0; } printf(")"); diff --git a/src/lisp/ao_lisp_const.lisp b/src/lisp/ao_lisp_const.lisp new file mode 100644 index 00000000..aa356d45 --- /dev/null +++ b/src/lisp/ao_lisp_const.lisp @@ -0,0 +1 @@ +cadr (lambda (l) (car (cdr l))) diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index 23908e64..b13d4681 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -40,8 +40,8 @@ static uint8_t been_here; #define DBG_POLY(a) #endif -ao_lisp_poly -ao_lisp_eval(ao_lisp_poly v) +ao_poly +ao_lisp_eval(ao_poly v) { struct ao_lisp_cons *formal; int cons = 0; @@ -59,6 +59,7 @@ ao_lisp_eval(ao_lisp_poly v) formals_tail = 0; for (;;) { + restart: /* Build stack frames for each list */ while (ao_lisp_poly_type(v) == AO_LISP_CONS) { if (v == AO_LISP_NIL) @@ -68,8 +69,8 @@ ao_lisp_eval(ao_lisp_poly v) if (cons++) { struct ao_lisp_cons *frame; - frame = ao_lisp_cons(ao_lisp_cons_poly(actuals), formals); - stack = ao_lisp_cons(ao_lisp_cons_poly(frame), stack); + frame = ao_lisp_cons_cons(ao_lisp_cons_poly(actuals), formals); + stack = ao_lisp_cons_cons(ao_lisp_cons_poly(frame), stack); } actuals = ao_lisp_poly_cons(v); formals = NULL; @@ -83,6 +84,8 @@ ao_lisp_eval(ao_lisp_poly v) /* Evaluate primitive types */ + DBG ("actual: "); DBG_POLY(v); DBG("\n"); + switch (ao_lisp_poly_type(v)) { case AO_LISP_INT: case AO_LISP_STRING: @@ -92,16 +95,42 @@ ao_lisp_eval(ao_lisp_poly v) break; } + if (!cons) + break; + for (;;) { DBG("add formal: "); DBG_POLY(v); DBG("\n"); - formal = ao_lisp_cons(v, NULL); + if (formals == NULL) { + if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) { + struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v); + switch (b->args) { + case AO_LISP_NLAMBDA: + v = ao_lisp_func(b)(ao_lisp_poly_cons(actuals->cdr)); + goto done_eval; + + case AO_LISP_MACRO: + v = ao_lisp_func(b)(ao_lisp_poly_cons(actuals->cdr)); + if (ao_lisp_poly_type(v) != AO_LISP_CONS) { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + + /* Reset frame to the new list */ + actuals = ao_lisp_poly_cons(v); + v = actuals->car; + goto restart; + } + } + } + + formal = ao_lisp_cons_cons(v, NULL); if (formals_tail) - formals_tail->cdr = formal; + formals_tail->cdr = ao_lisp_cons_poly(formal); else formals = formal; formals_tail = formal; - actuals = actuals->cdr; + actuals = ao_lisp_poly_cons(actuals->cdr); DBG("formals: "); DBG_CONS(formals); @@ -113,7 +142,6 @@ ao_lisp_eval(ao_lisp_poly v) /* Process all of the arguments */ if (actuals) { v = actuals->car; - DBG ("actual: "); DBG_POLY(v); DBG("\n"); break; } @@ -123,7 +151,7 @@ ao_lisp_eval(ao_lisp_poly v) if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) { struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v); - v = b->func(formals->cdr); + v = ao_lisp_func(b) (ao_lisp_poly_cons(formals->cdr)); DBG ("eval: "); DBG_CONS(formals); @@ -131,22 +159,23 @@ ao_lisp_eval(ao_lisp_poly v) DBG_POLY(v); DBG ("\n"); } else { - DBG ("invalid eval\n"); + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; } - + done_eval: if (--cons) { struct ao_lisp_cons *frame; /* Pop the previous frame off the stack */ frame = ao_lisp_poly_cons(stack->car); actuals = ao_lisp_poly_cons(frame->car); - formals = frame->cdr; + formals = ao_lisp_poly_cons(frame->cdr); /* Recompute the tail of the formals list */ - for (formal = formals; formal->cdr != NULL; formal = formal->cdr); + for (formal = formals; formal->cdr != AO_LISP_NIL; formal = ao_lisp_poly_cons(formal->cdr)); formals_tail = formal; - stack = stack->cdr; + stack = ao_lisp_poly_cons(stack->cdr); DBG("stack pop: stack"); DBG_CONS(stack); DBG("\n"); DBG("stack pop: actuals"); DBG_CONS(actuals); DBG("\n"); DBG("stack pop: formals"); DBG_CONS(formals); DBG("\n"); diff --git a/src/lisp/ao_lisp_int.c b/src/lisp/ao_lisp_int.c index 6ee3096d..77f65e95 100644 --- a/src/lisp/ao_lisp_int.c +++ b/src/lisp/ao_lisp_int.c @@ -15,7 +15,8 @@ #include "ao_lisp.h" void -ao_lisp_int_print(int i) +ao_lisp_int_print(ao_poly p) { + int i = ao_lisp_poly_int(p); printf("%d", i); } diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c new file mode 100644 index 00000000..21e000bf --- /dev/null +++ b/src/lisp/ao_lisp_make_const.c @@ -0,0 +1,90 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" +#include + +static struct ao_lisp_builtin * +ao_lisp_make_builtin(enum ao_lisp_builtin_id func, int args) { + struct ao_lisp_builtin *b = ao_lisp_alloc(sizeof (struct ao_lisp_builtin)); + + b->type = AO_LISP_BUILTIN; + b->func = func; + b->args = args; + return b; +} + +struct builtin_func { + char *name; + int args; + int func; +}; + +struct builtin_func funcs[] = { + "car", AO_LISP_LEXPR, builtin_car, + "cdr", AO_LISP_LEXPR, builtin_cdr, + "cons", AO_LISP_LEXPR, builtin_cons, + "quote", AO_LISP_NLAMBDA,builtin_quote, + "print", AO_LISP_LEXPR, builtin_print, + "+", AO_LISP_LEXPR, builtin_plus, + "-", AO_LISP_LEXPR, builtin_minus, + "*", AO_LISP_LEXPR, builtin_times, + "/", AO_LISP_LEXPR, builtin_divide, + "%", AO_LISP_LEXPR, builtin_mod +}; + +#define N_FUNC (sizeof funcs / sizeof funcs[0]) + +int +main(int argc, char **argv) +{ + int f, o; + ao_poly atom, val; + + for (f = 0; f < N_FUNC; f++) { + struct ao_lisp_builtin *b = ao_lisp_make_builtin(funcs[f].func, funcs[f].args); + struct ao_lisp_atom *a = ao_lisp_atom_intern(funcs[f].name); + a->val = ao_lisp_builtin_poly(b); + } + + for (;;) { + atom = ao_lisp_read(); + if (!atom) + break; + val = ao_lisp_read(); + if (!val) + break; + if (ao_lisp_poly_type(atom) != AO_LISP_ATOM) { + fprintf(stderr, "input must be atom val pairs\n"); + exit(1); + } + ao_lisp_poly_atom(atom)->val = val; + } + + printf("/* constant objects, all referenced from atoms */\n\n"); + printf("#define AO_LISP_POOL_CONST %d\n", ao_lisp_top); + printf("extern const uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4)));\n"); + printf("#define ao_builtin_atoms 0x%04x\n", ao_lisp_atom_poly(ao_lisp_atoms)); + printf("#ifdef AO_LISP_CONST_BITS\n"); + printf("const uint8_t ao_lisp_const[] = {"); + for (o = 0; o < ao_lisp_top; o++) { + if ((o & 0xf) == 0) + printf("\n\t"); + else + printf(" "); + printf("0x%02x,", ao_lisp_const[o]); + } + printf("\n};\n"); + printf("#endif /* AO_LISP_CONST_BITS */\n"); +} diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index d008519b..7295d150 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -12,23 +12,34 @@ * General Public License for more details. */ +#define AO_LISP_CONST_BITS + #include "ao_lisp.h" #include -uint8_t ao_lisp_pool[AO_LISP_POOL]; +uint8_t ao_lisp_pool[AO_LISP_POOL] __attribute__((aligned(4))); + +#ifdef AO_LISP_MAKE_CONST +#include +uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4))); +#endif + +uint8_t ao_lisp_exception; struct ao_lisp_root { void **addr; - const struct ao_lisp_mem_type *type; + const struct ao_lisp_type *type; }; +#define AO_LISP_ROOT 16 + static struct ao_lisp_root ao_lisp_root[AO_LISP_ROOT]; static uint8_t ao_lisp_busy[AO_LISP_POOL / 32]; static uint8_t ao_lisp_moving[AO_LISP_POOL / 32]; -static uint16_t ao_lisp_top; +uint16_t ao_lisp_top; static inline void mark(uint8_t *tag, int offset) { int byte = offset >> 5; @@ -59,9 +70,13 @@ static int mark_object(uint8_t *tag, void *addr, int size) { int base; int bound; + if (!addr) return 1; + if ((uint8_t *) addr < ao_lisp_pool || ao_lisp_pool + AO_LISP_POOL <= (uint8_t*) addr) + return 1; + base = (uint8_t *) addr - ao_lisp_pool; bound = base + size; @@ -150,7 +165,7 @@ collect(void) void -ao_lisp_mark(const struct ao_lisp_mem_type *type, void *addr) +ao_lisp_mark(const struct ao_lisp_type *type, void *addr) { if (mark_object(ao_lisp_busy, addr, type->size(addr))) return; @@ -175,7 +190,7 @@ check_move(void *addr, int size) } void * -ao_lisp_move(const struct ao_lisp_mem_type *type, void *addr) +ao_lisp_move(const struct ao_lisp_type *type, void *addr) { int size = type->size(addr); @@ -206,19 +221,29 @@ ao_lisp_alloc(int size) { void *addr; - size = (size + 3) & ~3; + size = ao_lisp_mem_round(size); +#ifdef AO_LISP_MAKE_CONST + if (ao_lisp_top + size > AO_LISP_POOL_CONST) { + fprintf(stderr, "Too much constant data, increase AO_LISP_POOL_CONST\n"); + exit(1); + } + addr = ao_lisp_const + ao_lisp_top; +#else if (ao_lisp_top + size > AO_LISP_POOL) { collect(); - if (ao_lisp_top + size > AO_LISP_POOL) + if (ao_lisp_top + size > AO_LISP_POOL) { + ao_lisp_exception |= AO_LISP_OOM; return NULL; + } } addr = ao_lisp_pool + ao_lisp_top; +#endif ao_lisp_top += size; return addr; } int -ao_lisp_root_add(const struct ao_lisp_mem_type *type, void *addr) +ao_lisp_root_add(const struct ao_lisp_type *type, void *addr) { int i; for (i = 0; i < AO_LISP_ROOT; i++) { diff --git a/src/lisp/ao_lisp_poly.c b/src/lisp/ao_lisp_poly.c index 1855d945..c6ca0a97 100644 --- a/src/lisp/ao_lisp_poly.c +++ b/src/lisp/ao_lisp_poly.c @@ -14,91 +14,7 @@ #include "ao_lisp.h" -enum math_op { math_plus, math_minus, math_times, math_divide, math_mod }; - -ao_lisp_poly -ao_lisp_math(struct ao_lisp_cons *cons, enum math_op op) -{ - ao_lisp_poly ret = AO_LISP_NIL; - - while (cons) { - ao_lisp_poly car = cons->car; - uint8_t rt = ao_lisp_poly_type(ret); - uint8_t ct = ao_lisp_poly_type(car); - - cons = cons->cdr; - - if (rt == AO_LISP_NIL) - ret = car; - - else if (rt == AO_LISP_INT && ct == AO_LISP_INT) { - int r = ao_lisp_poly_int(ret); - int c = ao_lisp_poly_int(car); - - switch(op) { - case math_plus: - r += c; - break; - case math_minus: - r -= c; - break; - case math_times: - r *= c; - break; - case math_divide: - if (c == 0) - return AO_LISP_NIL; - r /= c; - break; - case math_mod: - if (c == 0) - return AO_LISP_NIL; - r %= c; - break; - } - ret = ao_lisp_int_poly(r); - } - - else if (rt == AO_LISP_STRING && ct == AO_LISP_STRING && op == math_plus) - ret = ao_lisp_string_poly(ao_lisp_string_cat(ao_lisp_poly_string(ret), - ao_lisp_poly_string(car))); - else { - /* XXX exception */ - return AO_LISP_NIL; - } - } - return ret; -} - -ao_lisp_poly -ao_lisp_plus(struct ao_lisp_cons *cons) -{ - return ao_lisp_math(cons, math_plus); -} - -ao_lisp_poly -ao_lisp_minus(struct ao_lisp_cons *cons) -{ - return ao_lisp_math(cons, math_minus); -} - -ao_lisp_poly -ao_lisp_times(struct ao_lisp_cons *cons) -{ - return ao_lisp_math(cons, math_times); -} - -ao_lisp_poly -ao_lisp_divide(struct ao_lisp_cons *cons) -{ - return ao_lisp_math(cons, math_divide); -} - -ao_lisp_poly -ao_lisp_mod(struct ao_lisp_cons *cons) -{ - return ao_lisp_math(cons, math_mod); -} +/* static const struct ao_lisp_builtin builtin_plus = { .type = AO_LISP_BUILTIN, @@ -113,7 +29,6 @@ static const struct ao_lisp_atom atom_plus = { .name = "plus" }; -/* static const struct ao_lisp_builtin builtin_minus = { .type = AO_LISP_BUILTIN, .func = ao_lisp_minus @@ -124,9 +39,9 @@ static const struct ao_lisp_builtin builtin_times = { .func = ao_lisp_times }; -*/ const struct ao_lisp_atom const *ao_lisp_builtins[] = { &atom_plus, 0 }; +*/ diff --git a/src/lisp/ao_lisp_prim.c b/src/lisp/ao_lisp_prim.c index ccfd2be4..38dcb961 100644 --- a/src/lisp/ao_lisp_prim.c +++ b/src/lisp/ao_lisp_prim.c @@ -14,31 +14,25 @@ #include "ao_lisp.h" -ao_lisp_poly -ao_lisp_poly_print(ao_lisp_poly p) +static void (*const ao_lisp_print_funcs[AO_LISP_NUM_TYPE])(ao_poly) = { + [AO_LISP_CONS] = ao_lisp_cons_print, + [AO_LISP_STRING] = ao_lisp_string_print, + [AO_LISP_INT] = ao_lisp_int_print, + [AO_LISP_ATOM] = ao_lisp_atom_print, + [AO_LISP_BUILTIN] = ao_lisp_builtin_print +}; + +ao_poly +ao_lisp_poly_print(ao_poly p) { - switch (ao_lisp_poly_type(p)) { - case AO_LISP_CONS: - ao_lisp_cons_print(ao_lisp_poly_cons(p)); - break; - case AO_LISP_STRING: - ao_lisp_string_print(ao_lisp_poly_string(p)); - break; - case AO_LISP_INT: - ao_lisp_int_print(ao_lisp_poly_int(p)); - break; - case AO_LISP_ATOM: - ao_lisp_atom_print(ao_lisp_poly_atom(p)); - break; - case AO_LISP_BUILTIN: - ao_lisp_builtin_print(ao_lisp_poly_builtin(p)); - break; - } - return AO_LISP_NIL; + void (*print)(ao_poly) = ao_lisp_print_funcs[ao_lisp_poly_type(p)]; + if (print) + print(p); + return p; } void -ao_lisp_poly_mark(ao_lisp_poly p) +ao_lisp_poly_mark(ao_poly p) { switch (ao_lisp_poly_type(p)) { case AO_LISP_CONS: @@ -53,8 +47,8 @@ ao_lisp_poly_mark(ao_lisp_poly p) } } -ao_lisp_poly -ao_lisp_poly_move(ao_lisp_poly p) +ao_poly +ao_lisp_poly_move(ao_poly p) { switch (ao_lisp_poly_type(p)) { case AO_LISP_CONS: diff --git a/src/lisp/ao_lisp_read.c b/src/lisp/ao_lisp_read.c index ccb4ba3a..ea98b976 100644 --- a/src/lisp/ao_lisp_read.c +++ b/src/lisp/ao_lisp_read.c @@ -155,8 +155,21 @@ lex_get() if (lex_unget_c) { c = lex_unget_c; lex_unget_c = 0; - } else + } else { +#if AO_LISP_ALTOS + static uint8_t at_eol; + + if (at_eol) { + ao_cmd_readline(); + at_eol = 0; + } + c = ao_cmd_lex(); + if (c == '\n') + at_eol = 1; +#else c = getchar(); +#endif + } return c; } @@ -362,13 +375,13 @@ static struct ao_lisp_cons *read_cons; static struct ao_lisp_cons *read_cons_tail; static struct ao_lisp_cons *read_stack; -static ao_lisp_poly +static ao_poly read_item(void) { struct ao_lisp_atom *atom; char *string; int cons; - ao_lisp_poly v; + ao_poly v; if (!been_here) { ao_lisp_root_add(&ao_lisp_cons_type, &read_cons); @@ -381,7 +394,7 @@ read_item(void) for (;;) { while (parse_token == OPEN) { if (cons++) - read_stack = ao_lisp_cons(ao_lisp_cons_poly(read_cons), read_stack); + read_stack = ao_lisp_cons_cons(ao_lisp_cons_poly(read_cons), read_stack); read_cons = NULL; read_cons_tail = NULL; parse_token = lex(); @@ -416,10 +429,10 @@ read_item(void) v = AO_LISP_NIL; if (--cons) { read_cons = ao_lisp_poly_cons(read_stack->car); - read_stack = read_stack->cdr; + read_stack = ao_lisp_poly_cons(read_stack->cdr); for (read_cons_tail = read_cons; read_cons_tail && read_cons_tail->cdr; - read_cons_tail = read_cons_tail->cdr) + read_cons_tail = ao_lisp_poly_cons(read_cons_tail->cdr)) ; } break; @@ -428,9 +441,9 @@ read_item(void) if (!cons) break; - struct ao_lisp_cons *read = ao_lisp_cons(v, NULL); + struct ao_lisp_cons *read = ao_lisp_cons_cons(v, NULL); if (read_cons_tail) - read_cons_tail->cdr = read; + read_cons_tail->cdr = ao_lisp_cons_poly(read); else read_cons = read; read_cons_tail = read; @@ -440,7 +453,7 @@ read_item(void) return v; } -ao_lisp_poly +ao_poly ao_lisp_read(void) { parse_token = lex(); diff --git a/src/lisp/ao_lisp_rep.c b/src/lisp/ao_lisp_rep.c new file mode 100644 index 00000000..d26d270c --- /dev/null +++ b/src/lisp/ao_lisp_rep.c @@ -0,0 +1,40 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" + +ao_poly +ao_lisp_read_eval_print(void) +{ + ao_poly in, out = AO_LISP_NIL; + for(;;) { + in = ao_lisp_read(); + if (!in) + break; + out = ao_lisp_eval(in); + if (ao_lisp_exception) { + if (ao_lisp_exception & AO_LISP_OOM) + printf("out of memory\n"); + if (ao_lisp_exception & AO_LISP_DIVIDE_BY_ZERO) + printf("divide by zero\n"); + if (ao_lisp_exception & AO_LISP_INVALID) + printf("invalid operation\n"); + ao_lisp_exception = 0; + } else { + ao_lisp_poly_print(out); + putchar ('\n'); + } + } + return out; +} diff --git a/src/lisp/ao_lisp_string.c b/src/lisp/ao_lisp_string.c index 1ab56933..39c3dc81 100644 --- a/src/lisp/ao_lisp_string.c +++ b/src/lisp/ao_lisp_string.c @@ -68,16 +68,18 @@ ao_lisp_string_cat(char *a, char *b) return r; } -const struct ao_lisp_mem_type ao_lisp_string_type = { +const struct ao_lisp_type ao_lisp_string_type = { .mark = string_mark, .size = string_size, .move = string_move, }; void -ao_lisp_string_print(char *s) +ao_lisp_string_print(ao_poly p) { + char *s = ao_lisp_poly_string(p); char c; + putchar('"'); while ((c = *s++)) { switch (c) { diff --git a/src/nucleao-32/.gitignore b/src/nucleao-32/.gitignore new file mode 100644 index 00000000..cb8f78e5 --- /dev/null +++ b/src/nucleao-32/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +nucleo-32* diff --git a/src/nucleao-32/Makefile b/src/nucleao-32/Makefile index a160fd2f..0df44317 100644 --- a/src/nucleao-32/Makefile +++ b/src/nucleao-32/Makefile @@ -32,6 +32,17 @@ ALTOS_SRC = \ ao_mutex.c \ ao_usb_stm.c \ ao_serial_stm.c \ + ao_lisp_lex.c \ + ao_lisp_mem.c \ + ao_lisp_cons.c \ + ao_lisp_eval.c \ + ao_lisp_string.c \ + ao_lisp_atom.c \ + ao_lisp_int.c \ + ao_lisp_prim.c \ + ao_lisp_builtin.c \ + ao_lisp_read.c \ + ao_lisp_rep.c \ ao_exti_stm.c PRODUCT=Nucleo-32 diff --git a/src/nucleao-32/ao_nucleo.c b/src/nucleao-32/ao_nucleo.c index cda889c6..113e2399 100644 --- a/src/nucleao-32/ao_nucleo.c +++ b/src/nucleao-32/ao_nucleo.c @@ -13,6 +13,7 @@ */ #include +#include static uint16_t blink_delay, blink_running; @@ -41,11 +42,17 @@ static void blink_cmd() { ao_sleep(&blink_running); } +static void lisp_cmd() { + ao_lisp_read_eval_print(); +} + static const struct ao_cmds blink_cmds[] = { { blink_cmd, "b \0Blink the green LED" }, + { lisp_cmd, "l\0Run lisp interpreter" }, { 0, 0 } }; + void main(void) { ao_led_init(LEDS_AVAILABLE); diff --git a/src/nucleao-32/flash-loader/.gitignore b/src/nucleao-32/flash-loader/.gitignore new file mode 100644 index 00000000..cb8f78e5 --- /dev/null +++ b/src/nucleao-32/flash-loader/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +nucleo-32* diff --git a/src/test/Makefile b/src/test/Makefile index e841bfde..6c51c421 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -10,7 +10,7 @@ INCS=ao_kalman.h ao_ms5607.h ao_log.h ao_data.h altitude-pa.h altitude.h ao_quat KALMAN=make-kalman -CFLAGS=-I.. -I. -I../kernel -I../drivers -I../micropeak -I../product -I../lisp -O0 -g -Wall +CFLAGS=-I.. -I. -I../kernel -I../drivers -I../micropeak -I../product -I../lisp -O0 -g -Wall -DAO_LISP_TEST all: $(PROGS) ao_aprs_data.wav @@ -89,9 +89,11 @@ ao_quaternion_test: ao_quaternion_test.c ao_quaternion.h cc $(CFLAGS) -o $@ ao_quaternion_test.c -lm -AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o ao_lisp_lex.o ao_lisp_cons.o ao_lisp_string.o ao_lisp_atom.o ao_lisp_int.o ao_lisp_prim.o ao_lisp_eval.o ao_lisp_poly.o ao_lisp_builtin.o ao_lisp_read.o +#AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o ao_lisp_lex.o ao_lisp_cons.o ao_lisp_string.o ao_lisp_atom.o ao_lisp_int.o ao_lisp_prim.o ao_lisp_eval.o ao_lisp_poly.o ao_lisp_builtin.o ao_lisp_read.o + +AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o ao_lisp_cons.o ao_lisp_string.o ao_lisp_atom.o ao_lisp_int.o ao_lisp_prim.o ao_lisp_eval.o ao_lisp_poly.o ao_lisp_builtin.o ao_lisp_read.o ao_lisp_rep.o ao_lisp_test: $(AO_LISP_OBJS) cc $(CFLAGS) -o $@ $(AO_LISP_OBJS) -$(AO_LISP_OBJS): ao_lisp.h +$(AO_LISP_OBJS): ao_lisp.h ao_lisp_const.h diff --git a/src/test/ao_lisp_test.c b/src/test/ao_lisp_test.c index 96f1fd72..810a1528 100644 --- a/src/test/ao_lisp_test.c +++ b/src/test/ao_lisp_test.c @@ -21,9 +21,9 @@ static char *string; int main (int argc, char **argv) { - int i, j; + int i, j; struct ao_lisp_atom *atom; - ao_lisp_poly poly; + ao_lisp_root_add(&ao_lisp_cons_type, (void **) &list); ao_lisp_root_add(&ao_lisp_string_type, (void **) &string); @@ -31,37 +31,35 @@ main (int argc, char **argv) for (j = 0; j < 10; j++) { list = 0; string = ao_lisp_string_new(0); - for (i = 0; i < 7; i++) { + for (i = 0; i < 2; i++) { string = ao_lisp_string_cat(string, "a"); - list = ao_lisp_cons(ao_lisp_string_poly(string), list); - list = ao_lisp_cons(ao_lisp_int_poly(i), list); + list = ao_lisp_cons_cons(ao_lisp_string_poly(string), list); + list = ao_lisp_cons_cons(ao_lisp_int_poly(i), list); atom = ao_lisp_atom_intern("ant"); atom->val = ao_lisp_cons_poly(list); - list = ao_lisp_cons(ao_lisp_atom_poly(atom), list); + list = ao_lisp_cons_cons(ao_lisp_atom_poly(atom), list); } ao_lisp_poly_print(ao_lisp_cons_poly(list)); printf("\n"); } - atom = ao_lisp_atom_intern("ant"); - atom->val = ao_lisp_string_poly(ao_lisp_string_cat("hello world", "")); - - list = ao_lisp_cons(ao_lisp_atom_poly(ao_lisp_atom_intern("plus")), - ao_lisp_cons(ao_lisp_cons_poly(ao_lisp_cons(ao_lisp_atom_poly(ao_lisp_atom_intern("plus")), - ao_lisp_cons(ao_lisp_int_poly(3), - ao_lisp_cons(ao_lisp_int_poly(4), NULL)))), - ao_lisp_cons(ao_lisp_int_poly(2), NULL))); + for (atom = ao_lisp_poly_atom(ao_builtin_atoms); atom; atom = ao_lisp_poly_atom(atom->next)) { + printf("%s = ", atom->name); + ao_lisp_poly_print(atom->val); + printf("\n"); + } +#if 1 + list = ao_lisp_cons_cons(ao_lisp_atom_poly(ao_lisp_atom_intern("+")), + ao_lisp_cons_cons(ao_lisp_cons_poly(ao_lisp_cons_cons(ao_lisp_atom_poly(ao_lisp_atom_intern("+")), + ao_lisp_cons_cons(ao_lisp_int_poly(3), + ao_lisp_cons_cons(ao_lisp_int_poly(4), NULL)))), + ao_lisp_cons_cons(ao_lisp_int_poly(2), NULL))); printf("list: "); ao_lisp_poly_print(ao_lisp_cons_poly(list)); printf ("\n"); ao_lisp_poly_print(ao_lisp_eval(ao_lisp_cons_poly(list))); printf ("\n"); - while ((poly = ao_lisp_read())) { - poly = ao_lisp_eval(poly); - ao_lisp_poly_print(poly); - putchar ('\n'); - fflush(stdout); - } - + ao_lisp_read_eval_print(); +#endif } -- cgit v1.2.3 From caba623cb013b73e1f0ca369edf98e0376bec41a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 2 Nov 2016 14:14:23 -0700 Subject: altos/kernel: Make ao_cmd_readline public. Return char from ao_cmd_lex. With these two changes, the readline function can be used by other code. Signed-off-by: Keith Packard --- src/kernel/ao.h | 3 +++ src/kernel/ao_cmd.c | 19 +++++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/kernel/ao.h b/src/kernel/ao.h index fb41d7a9..9ab7991b 100644 --- a/src/kernel/ao.h +++ b/src/kernel/ao.h @@ -170,6 +170,9 @@ void ao_put_string(__code char *s); void +ao_cmd_readline(void); + +char ao_cmd_lex(void); void diff --git a/src/kernel/ao_cmd.c b/src/kernel/ao_cmd.c index 10716afd..077d7de1 100644 --- a/src/kernel/ao_cmd.c +++ b/src/kernel/ao_cmd.c @@ -24,13 +24,15 @@ __pdata uint32_t ao_cmd_lex_u32; __pdata char ao_cmd_lex_c; __pdata enum ao_cmd_status ao_cmd_status; +#ifndef AO_CMD_LEN #if AO_PYRO_NUM -#define CMD_LEN 128 +#define AO_CMD_LEN 128 #else -#define CMD_LEN 48 +#define AO_CMD_LEN 48 +#endif #endif -static __xdata char cmd_line[CMD_LEN]; +static __xdata char cmd_line[AO_CMD_LEN]; static __pdata uint8_t cmd_len; static __pdata uint8_t cmd_i; @@ -48,8 +50,8 @@ backspace(void) ao_put_string ("\010 \010"); } -static void -readline(void) +void +ao_cmd_readline(void) { char c; if (ao_echo()) @@ -88,7 +90,7 @@ readline(void) break; } - if (cmd_len >= CMD_LEN - 2) + if (cmd_len >= AO_CMD_LEN - 2) continue; cmd_line[cmd_len++] = c; if (ao_echo()) @@ -99,12 +101,13 @@ readline(void) cmd_i = 0; } -void +char ao_cmd_lex(void) { ao_cmd_lex_c = '\n'; if (cmd_i < cmd_len) ao_cmd_lex_c = cmd_line[cmd_i++]; + return ao_cmd_lex_c; } static void @@ -376,7 +379,7 @@ ao_cmd(void) void (*__xdata func)(void); for (;;) { - readline(); + ao_cmd_readline(); ao_cmd_lex(); ao_cmd_white(); c = ao_cmd_lex_c; -- cgit v1.2.3 From 8362393a621ea78a96e7f65f602f4bfc7bbd1158 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 2 Nov 2016 14:18:31 -0700 Subject: altos/stmf0: Add lisp to include directories Signed-off-by: Keith Packard --- src/stmf0/Makefile-stmf0.defs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/stmf0/Makefile-stmf0.defs b/src/stmf0/Makefile-stmf0.defs index 0ccfbe2a..2ea3d1d8 100644 --- a/src/stmf0/Makefile-stmf0.defs +++ b/src/stmf0/Makefile-stmf0.defs @@ -27,7 +27,10 @@ CC=$(ARM_CC) WARN_FLAGS=-Wall -Wextra -Werror -Wcast-align -AO_CFLAGS=-I. -I$(TOPDIR)/stmf0 -I$(TOPDIR)/kernel -I$(TOPDIR)/drivers -I$(TOPDIR)/product -I$(TOPDIR) -I$(TOPDIR)/math $(PDCLIB_INCLUDES) +AO_CFLAGS=-I. -I$(TOPDIR)/stmf0 -I$(TOPDIR)/kernel -I$(TOPDIR)/drivers \ + -I$(TOPDIR)/product -I$(TOPDIR) -I$(TOPDIR)/math -I$(TOPDIR)/lisp \ + $(PDCLIB_INCLUDES) + STMF0_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m0 -mthumb\ -ffreestanding -nostdlib $(AO_CFLAGS) $(WARN_FLAGS) -- cgit v1.2.3 From 9e1a787f8828fb7b750ad3310c89a89536ea5286 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 2 Nov 2016 14:18:54 -0700 Subject: altos/lisp: add set/setq and ' in reader Along with other small fixes Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 8 ++++ src/lisp/ao_lisp_builtin.c | 76 ++++++++++++++++++++++++++---- src/lisp/ao_lisp_eval.c | 13 ++++-- src/lisp/ao_lisp_make_const.c | 23 ++++++++- src/lisp/ao_lisp_read.c | 105 +++++++++++++++++++++++++++++------------- src/lisp/ao_lisp_rep.c | 1 + 6 files changed, 183 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 4fac861b..d4108662 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -27,6 +27,7 @@ #ifdef AO_LISP_MAKE_CONST #define AO_LISP_POOL_CONST 16384 extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST]; +#define _ao_lisp_atom_quote ao_lisp_atom_poly(ao_lisp_atom_intern("quote")) #else #include "ao_lisp_const.h" #endif @@ -62,6 +63,11 @@ extern uint8_t ao_lisp_exception; typedef uint16_t ao_poly; +static inline int +ao_lisp_is_const(ao_poly poly) { + return poly & AO_LISP_CONST; +} + static inline void * ao_lisp_ref(ao_poly poly) { if (poly == AO_LISP_NIL) @@ -128,6 +134,8 @@ enum ao_lisp_builtin_id { builtin_cdr, builtin_cons, builtin_quote, + builtin_set, + builtin_setq, builtin_print, builtin_plus, builtin_minus, diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index e6d55797..63fb69fd 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -21,20 +21,46 @@ ao_lisp_builtin_print(ao_poly b) printf("[builtin]"); } +static int check_argc(struct ao_lisp_cons *cons, int min, int max) +{ + int argc = 0; + + while (cons && argc <= max) { + argc++; + cons = ao_lisp_poly_cons(cons->cdr); + } + if (argc < min || argc > max) { + ao_lisp_exception |= AO_LISP_INVALID; + return 0; + } + return 1; +} + +static int check_argt(struct ao_lisp_cons *cons, int argc, int type, int nil_ok) +{ + ao_poly car; + + /* find the desired arg */ + while (argc--) + cons = ao_lisp_poly_cons(cons->cdr); + car = cons->car; + if ((!car && !nil_ok) || + ao_lisp_poly_type(car) != type) + { + ao_lisp_exception |= AO_LISP_INVALID; + return 0; + } + return 1; +} + enum math_op { math_plus, math_minus, math_times, math_divide, math_mod }; ao_poly ao_lisp_car(struct ao_lisp_cons *cons) { - if (!cons) { - ao_lisp_exception |= AO_LISP_INVALID; - return AO_LISP_NIL; - } - if (!cons->car) { - ao_lisp_exception |= AO_LISP_INVALID; + if (!check_argc(cons, 1, 1)) return AO_LISP_NIL; - } - if (ao_lisp_poly_type(cons->car) != AO_LISP_CONS) { + if (!check_argt(cons, 0, AO_LISP_CONS, 0)) { ao_lisp_exception |= AO_LISP_INVALID; return AO_LISP_NIL; } @@ -91,6 +117,38 @@ ao_lisp_quote(struct ao_lisp_cons *cons) return cons->car; } +ao_poly +ao_lisp_set(struct ao_lisp_cons *cons) +{ + ao_poly atom, val; + if (!check_argc(cons, 2, 2)) + return AO_LISP_NIL; + if (!check_argt(cons, 0, AO_LISP_ATOM, 0)) + return AO_LISP_NIL; + + atom = cons->car; + val = ao_lisp_poly_cons(cons->cdr)->car; + if (ao_lisp_is_const(atom)) { + ao_lisp_exception |= AO_LISP_INVALID; + return AO_LISP_NIL; + } + ao_lisp_poly_atom(atom)->val = val; + return val; +} + +ao_poly +ao_lisp_setq(struct ao_lisp_cons *cons) +{ + struct ao_lisp_cons *expand = 0; + if (!check_argc(cons, 2, 2)) + return AO_LISP_NIL; + expand = ao_lisp_cons_cons(_ao_lisp_atom_set, + ao_lisp_cons_cons(ao_lisp_cons_poly(ao_lisp_cons_cons(_ao_lisp_atom_quote, + ao_lisp_cons_cons(cons->car, NULL))), + ao_lisp_poly_cons(cons->cdr))); + return ao_lisp_cons_poly(expand); +} + ao_poly ao_lisp_print(struct ao_lisp_cons *cons) { @@ -196,6 +254,8 @@ ao_lisp_func_t ao_lisp_builtins[] = { [builtin_cdr] = ao_lisp_cdr, [builtin_cons] = ao_lisp_cons, [builtin_quote] = ao_lisp_quote, + [builtin_set] = ao_lisp_set, + [builtin_setq] = ao_lisp_setq, [builtin_print] = ao_lisp_print, [builtin_plus] = ao_lisp_plus, [builtin_minus] = ao_lisp_minus, diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index b13d4681..2374fdb2 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -111,6 +111,9 @@ ao_lisp_eval(ao_poly v) case AO_LISP_MACRO: v = ao_lisp_func(b)(ao_lisp_poly_cons(actuals->cdr)); + DBG("macro "); DBG_POLY(ao_lisp_cons_poly(actuals)); + DBG(" -> "); DBG_POLY(v); + DBG("\n"); if (ao_lisp_poly_type(v) != AO_LISP_CONS) { ao_lisp_exception |= AO_LISP_INVALID; return AO_LISP_NIL; @@ -160,8 +163,9 @@ ao_lisp_eval(ao_poly v) DBG ("\n"); } else { ao_lisp_exception |= AO_LISP_INVALID; - return AO_LISP_NIL; } + if (ao_lisp_exception) + return AO_LISP_NIL; done_eval: if (--cons) { struct ao_lisp_cons *frame; @@ -170,10 +174,13 @@ ao_lisp_eval(ao_poly v) frame = ao_lisp_poly_cons(stack->car); actuals = ao_lisp_poly_cons(frame->car); formals = ao_lisp_poly_cons(frame->cdr); + formals_tail = NULL; /* Recompute the tail of the formals list */ - for (formal = formals; formal->cdr != AO_LISP_NIL; formal = ao_lisp_poly_cons(formal->cdr)); - formals_tail = formal; + if (formals) { + for (formal = formals; formal->cdr != AO_LISP_NIL; formal = ao_lisp_poly_cons(formal->cdr)); + formals_tail = formal; + } stack = ao_lisp_poly_cons(stack->cdr); DBG("stack pop: stack"); DBG_CONS(stack); DBG("\n"); diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index 21e000bf..8d3e03a9 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -14,6 +14,7 @@ #include "ao_lisp.h" #include +#include static struct ao_lisp_builtin * ao_lisp_make_builtin(enum ao_lisp_builtin_id func, int args) { @@ -36,6 +37,8 @@ struct builtin_func funcs[] = { "cdr", AO_LISP_LEXPR, builtin_cdr, "cons", AO_LISP_LEXPR, builtin_cons, "quote", AO_LISP_NLAMBDA,builtin_quote, + "set", AO_LISP_LEXPR, builtin_set, + "setq", AO_LISP_MACRO, builtin_setq, "print", AO_LISP_LEXPR, builtin_print, "+", AO_LISP_LEXPR, builtin_plus, "-", AO_LISP_LEXPR, builtin_minus, @@ -51,6 +54,7 @@ main(int argc, char **argv) { int f, o; ao_poly atom, val; + struct ao_lisp_atom *a; for (f = 0; f < N_FUNC; f++) { struct ao_lisp_builtin *b = ao_lisp_make_builtin(funcs[f].func, funcs[f].args); @@ -76,14 +80,31 @@ main(int argc, char **argv) printf("#define AO_LISP_POOL_CONST %d\n", ao_lisp_top); printf("extern const uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4)));\n"); printf("#define ao_builtin_atoms 0x%04x\n", ao_lisp_atom_poly(ao_lisp_atoms)); + + for (a = ao_lisp_atoms; a; a = ao_lisp_poly_atom(a->next)) { + char *n = a->name, c; + printf ("#define _ao_lisp_atom_"); + while ((c = *n++)) { + if (isalnum(c)) + printf("%c", c); + else + printf("%02x", c); + } + printf(" 0x%04x\n", ao_lisp_atom_poly(a)); + } printf("#ifdef AO_LISP_CONST_BITS\n"); printf("const uint8_t ao_lisp_const[] = {"); for (o = 0; o < ao_lisp_top; o++) { + uint8_t c; if ((o & 0xf) == 0) printf("\n\t"); else printf(" "); - printf("0x%02x,", ao_lisp_const[o]); + c = ao_lisp_const[o]; + if (' ' < c && c <= '~' && c != '\'') + printf (" '%c',", c); + else + printf("0x%02x,", c); } printf("\n};\n"); printf("#endif /* AO_LISP_CONST_BITS */\n"); diff --git a/src/lisp/ao_lisp_read.c b/src/lisp/ao_lisp_read.c index ea98b976..8fc134e5 100644 --- a/src/lisp/ao_lisp_read.c +++ b/src/lisp/ao_lisp_read.c @@ -375,12 +375,45 @@ static struct ao_lisp_cons *read_cons; static struct ao_lisp_cons *read_cons_tail; static struct ao_lisp_cons *read_stack; -static ao_poly -read_item(void) +static int +push_read_stack(int cons, int in_quote) +{ + if (cons) { + read_stack = ao_lisp_cons_cons(ao_lisp_cons_poly(read_cons), + ao_lisp_cons_cons(ao_lisp_int_poly(in_quote), + read_stack)); + if (!read_stack) + return 0; + } + read_cons = NULL; + read_cons_tail = NULL; + return 1; +} + +static int +pop_read_stack(int cons) +{ + int in_quote = 0; + if (cons) { + read_cons = ao_lisp_poly_cons(read_stack->car); + read_stack = ao_lisp_poly_cons(read_stack->cdr); + in_quote = ao_lisp_poly_int(read_stack->car); + read_stack = ao_lisp_poly_cons(read_stack->cdr); + for (read_cons_tail = read_cons; + read_cons_tail && read_cons_tail->cdr; + read_cons_tail = ao_lisp_poly_cons(read_cons_tail->cdr)) + ; + } + return in_quote; +} + +ao_poly +ao_lisp_read(void) { struct ao_lisp_atom *atom; char *string; int cons; + int in_quote; ao_poly v; if (!been_here) { @@ -388,15 +421,17 @@ read_item(void) ao_lisp_root_add(&ao_lisp_cons_type, &read_cons_tail); ao_lisp_root_add(&ao_lisp_cons_type, &read_stack); } + parse_token = lex(); cons = 0; + in_quote = 0; read_cons = read_cons_tail = read_stack = 0; for (;;) { while (parse_token == OPEN) { - if (cons++) - read_stack = ao_lisp_cons_cons(ao_lisp_cons_poly(read_cons), read_stack); - read_cons = NULL; - read_cons_tail = NULL; + if (!push_read_stack(cons, in_quote)) + return AO_LISP_NIL; + cons++; + in_quote = 0; parse_token = lex(); } @@ -422,40 +457,48 @@ read_item(void) else v = AO_LISP_NIL; break; + case QUOTE: + if (!push_read_stack(cons, in_quote)) + return AO_LISP_NIL; + cons++; + in_quote = 1; + v = _ao_lisp_atom_quote; + break; case CLOSE: - if (cons) - v = ao_lisp_cons_poly(read_cons); - else + if (!cons) { v = AO_LISP_NIL; - if (--cons) { - read_cons = ao_lisp_poly_cons(read_stack->car); - read_stack = ao_lisp_poly_cons(read_stack->cdr); - for (read_cons_tail = read_cons; - read_cons_tail && read_cons_tail->cdr; - read_cons_tail = ao_lisp_poly_cons(read_cons_tail->cdr)) - ; + break; } + v = ao_lisp_cons_poly(read_cons); + --cons; + in_quote = pop_read_stack(cons); break; } - if (!cons) - break; + /* loop over QUOTE ends */ + for (;;) { + if (!cons) + return v; + + struct ao_lisp_cons *read = ao_lisp_cons_cons(v, NULL); + if (!read) + return AO_LISP_NIL; + + if (read_cons_tail) + read_cons_tail->cdr = ao_lisp_cons_poly(read); + else + read_cons = read; + read_cons_tail = read; + + if (!in_quote || !read_cons->cdr) + break; - struct ao_lisp_cons *read = ao_lisp_cons_cons(v, NULL); - if (read_cons_tail) - read_cons_tail->cdr = ao_lisp_cons_poly(read); - else - read_cons = read; - read_cons_tail = read; + v = ao_lisp_cons_poly(read_cons); + --cons; + in_quote = pop_read_stack(cons); + } parse_token = lex(); } return v; } - -ao_poly -ao_lisp_read(void) -{ - parse_token = lex(); - return read_item(); -} diff --git a/src/lisp/ao_lisp_rep.c b/src/lisp/ao_lisp_rep.c index d26d270c..a1f9fa1f 100644 --- a/src/lisp/ao_lisp_rep.c +++ b/src/lisp/ao_lisp_rep.c @@ -22,6 +22,7 @@ ao_lisp_read_eval_print(void) in = ao_lisp_read(); if (!in) break; +// printf ("in: "); ao_lisp_poly_print(in); printf("\n"); out = ao_lisp_eval(in); if (ao_lisp_exception) { if (ao_lisp_exception & AO_LISP_OOM) -- cgit v1.2.3 From 11cb03b1d336ee90c422be27588f57be573a9546 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 2 Nov 2016 22:56:01 -0700 Subject: altos/lisp: Separate out values from atoms This enables changing values of atoms declared as constants, should enable lets, and with some work, even lexical scoping. this required changing the constant computation to run ao_lisp_collect() before dumping the block of constant data, and that uncovered some minor memory manager bugs. Signed-off-by: Keith Packard --- src/lisp/Makefile | 3 +- src/lisp/ao_lisp.h | 105 +++++++++++++++++------ src/lisp/ao_lisp_atom.c | 51 +++++++++-- src/lisp/ao_lisp_builtin.c | 37 ++++++-- src/lisp/ao_lisp_cons.c | 27 +++++- src/lisp/ao_lisp_eval.c | 5 +- src/lisp/ao_lisp_frame.c | 191 ++++++++++++++++++++++++++++++++++++++++++ src/lisp/ao_lisp_make_const.c | 44 ++++++++-- src/lisp/ao_lisp_mem.c | 168 +++++++++++++++++++++++++++++++------ src/lisp/ao_lisp_prim.c | 41 +++++---- src/lisp/ao_lisp_read.c | 23 ++--- src/nucleao-32/Makefile | 3 + src/test/Makefile | 4 +- src/test/ao_lisp_test.c | 3 +- 14 files changed, 597 insertions(+), 108 deletions(-) create mode 100644 src/lisp/ao_lisp_frame.c (limited to 'src') diff --git a/src/lisp/Makefile b/src/lisp/Makefile index e8c3c02c..9e2fb58c 100644 --- a/src/lisp/Makefile +++ b/src/lisp/Makefile @@ -16,7 +16,8 @@ SRCS=\ ao_lisp_poly.c \ ao_lisp_prim.c \ ao_lisp_builtin.c \ - ao_lisp_read.c + ao_lisp_read.c \ + ao_lisp_frame.c OBJS=$(SRCS:.c=.o) diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index d4108662..98e99acb 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -15,9 +15,12 @@ #ifndef _AO_LISP_H_ #define _AO_LISP_H_ +#include + #if !defined(AO_LISP_TEST) && !defined(AO_LISP_MAKE_CONST) #include #define AO_LISP_ALTOS 1 +#define abort() ao_panic(1) #endif #include @@ -27,9 +30,14 @@ #ifdef AO_LISP_MAKE_CONST #define AO_LISP_POOL_CONST 16384 extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST]; +#define ao_lisp_pool ao_lisp_const +#define AO_LISP_POOL AO_LISP_POOL_CONST #define _ao_lisp_atom_quote ao_lisp_atom_poly(ao_lisp_atom_intern("quote")) +#define _ao_lisp_atom_set ao_lisp_atom_poly(ao_lisp_atom_intern("set")) #else #include "ao_lisp_const.h" +#define AO_LISP_POOL 1024 +extern uint8_t ao_lisp_pool[AO_LISP_POOL]; #endif /* Primitive types */ @@ -46,13 +54,11 @@ extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST]; /* These have a type value at the start of the struct */ #define AO_LISP_ATOM 4 #define AO_LISP_BUILTIN 5 -#define AO_LISP_NUM_TYPE 6 +#define AO_LISP_FRAME 6 +#define AO_LISP_NUM_TYPE 7 #define AO_LISP_NIL 0 -#define AO_LISP_POOL 1024 - -extern uint8_t ao_lisp_pool[AO_LISP_POOL]; extern uint16_t ao_lisp_top; #define AO_LISP_OOM 0x01 @@ -68,37 +74,31 @@ ao_lisp_is_const(ao_poly poly) { return poly & AO_LISP_CONST; } +#define AO_LISP_POOL_BASE (ao_lisp_pool - 4) +#define AO_LISP_CONST_BASE (ao_lisp_const - 4) + +#define AO_LISP_IS_CONST(a) (ao_lisp_const <= ((uint8_t *) (a)) && ((uint8_t *) (a)) < ao_lisp_const + AO_LISP_POOL_CONST) +#define AO_LISP_IS_POOL(a) (ao_lisp_pool <= ((uint8_t *) (a)) && ((uint8_t *) (a)) < ao_lisp_pool + AO_LISP_POOL) + static inline void * ao_lisp_ref(ao_poly poly) { if (poly == AO_LISP_NIL) return NULL; if (poly & AO_LISP_CONST) - return (void *) ((ao_lisp_const - 4) + (poly & AO_LISP_REF_MASK)); - else - return (void *) ((ao_lisp_pool - 4) + (poly & AO_LISP_REF_MASK)); + return (void *) (AO_LISP_CONST_BASE + (poly & AO_LISP_REF_MASK)); + return (void *) (AO_LISP_POOL_BASE + (poly & AO_LISP_REF_MASK)); } static inline ao_poly ao_lisp_poly(const void *addr, ao_poly type) { const uint8_t *a = addr; - if (addr == NULL) + if (a == NULL) return AO_LISP_NIL; - if (ao_lisp_pool <= a && a < ao_lisp_pool + AO_LISP_POOL) - return (a - (ao_lisp_pool - 4)) | type; - else if (ao_lisp_const <= a && a <= ao_lisp_const + AO_LISP_POOL_CONST) - return AO_LISP_CONST | (a - (ao_lisp_const - 4)) | type; - else { - ao_lisp_exception |= AO_LISP_INVALID; - return AO_LISP_NIL; - } + if (AO_LISP_IS_CONST(a)) + return AO_LISP_CONST | (a - AO_LISP_CONST_BASE) | type; + return (a - AO_LISP_POOL_BASE) | type; } -#define AO_LISP_POLY(addr, type) (((ao_lisp_pool <= ((uint8_t *) (a)) && \ - ((uint8_t *) (a)) < ao_lisp_pool + AO_LISP_POOL) ? \ - ((uint8_t *) (a) - (ao_lisp_pool - 4)) : \ - (((uint8_t *) (a) - (ao_lisp_const - 4)) | AO_LISP_POOL_CONST)) | \ - (type)) - struct ao_lisp_type { void (*mark)(void *addr); int (*size)(void *addr); @@ -113,11 +113,32 @@ struct ao_lisp_cons { struct ao_lisp_atom { uint8_t type; uint8_t pad[1]; - ao_poly val; ao_poly next; char name[]; }; +struct ao_lisp_val { + ao_poly atom; + ao_poly val; +}; + +struct ao_lisp_frame { + uint8_t num; + uint8_t readonly; + ao_poly next; + struct ao_lisp_val vals[]; +}; + +static inline struct ao_lisp_frame * +ao_lisp_poly_frame(ao_poly poly) { + return ao_lisp_ref(poly); +} + +static inline ao_poly +ao_lisp_frame_poly(struct ao_lisp_frame *frame) { + return ao_lisp_poly(frame, AO_LISP_OTHER); +} + #define AO_LISP_LAMBDA 0 #define AO_LISP_NLAMBDA 1 #define AO_LISP_MACRO 2 @@ -160,6 +181,11 @@ ao_lisp_poly_other(ao_poly poly) { return ao_lisp_ref(poly); } +static inline uint8_t +ao_lisp_other_type(void *other) { + return *((uint8_t *) other); +} + static inline ao_poly ao_lisp_other_poly(const void *other) { @@ -175,9 +201,9 @@ ao_lisp_mem_round(int size) #define AO_LISP_OTHER_POLY(other) ((ao_poly)(other) + AO_LISP_OTHER) static inline int ao_lisp_poly_type(ao_poly poly) { - int type = poly & 3; + int type = poly & AO_LISP_TYPE_MASK; if (type == AO_LISP_OTHER) - return *((uint8_t *) ao_lisp_poly_other(poly)); + return ao_lisp_other_type(ao_lisp_poly_other(poly)); return type; } @@ -249,6 +275,9 @@ ao_lisp_mark(const struct ao_lisp_type *type, void *addr); int ao_lisp_mark_memory(void *addr, int size); +void * +ao_lisp_move_map(void *addr); + void * ao_lisp_move(const struct ao_lisp_type *type, void *addr); @@ -259,6 +288,9 @@ ao_lisp_move_memory(void *addr, int size); void * ao_lisp_alloc(int size); +void +ao_lisp_collect(void); + int ao_lisp_root_add(const struct ao_lisp_type *type, void *addr); @@ -303,6 +335,12 @@ ao_lisp_atom_print(ao_poly a); struct ao_lisp_atom * ao_lisp_atom_intern(char *name); +ao_poly +ao_lisp_atom_get(ao_poly atom); + +ao_poly +ao_lisp_atom_set(ao_poly atom, ao_poly val); + /* int */ void ao_lisp_int_print(ao_poly i); @@ -325,6 +363,8 @@ ao_lisp_eval(ao_poly p); void ao_lisp_builtin_print(ao_poly b); +extern const struct ao_lisp_type ao_lisp_builtin_type; + /* read */ ao_poly ao_lisp_read(void); @@ -333,4 +373,19 @@ ao_lisp_read(void); ao_poly ao_lisp_read_eval_print(void); +/* frame */ +extern const struct ao_lisp_type ao_lisp_frame_type; + +int +ao_lisp_frame_set(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val); + +ao_poly +ao_lisp_frame_get(struct ao_lisp_frame *frame, ao_poly atom); + +struct ao_lisp_frame * +ao_lisp_frame_new(int num, int readonly); + +struct ao_lisp_frame * +ao_lisp_frame_add(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val); + #endif /* _AO_LISP_H_ */ diff --git a/src/lisp/ao_lisp_atom.c b/src/lisp/ao_lisp_atom.c index aaa84b8d..e5d28c3b 100644 --- a/src/lisp/ao_lisp_atom.c +++ b/src/lisp/ao_lisp_atom.c @@ -17,6 +17,12 @@ #include "ao_lisp.h" +#if 0 +#define DBG(...) printf(__VA_ARGS__) +#else +#define DBG(...) +#endif + static int name_size(char *name) { return sizeof(struct ao_lisp_atom) + strlen(name) + 1; @@ -34,31 +40,38 @@ static void atom_mark(void *addr) { struct ao_lisp_atom *atom = addr; + DBG ("\tatom start %s\n", atom->name); for (;;) { - ao_lisp_poly_mark(atom->val); atom = ao_lisp_poly_atom(atom->next); if (!atom) break; + DBG("\t\tatom mark %s %d\n", atom->name, (uint8_t *) atom - ao_lisp_const); if (ao_lisp_mark_memory(atom, atom_size(atom))) break; } + DBG ("\tatom done\n"); } static void atom_move(void *addr) { struct ao_lisp_atom *atom = addr; + DBG("\tatom move start %s %d next %s %d\n", + atom->name, ((uint8_t *) atom - ao_lisp_const), + atom->next ? ao_lisp_poly_atom(atom->next)->name : "(none)", + atom->next ? ((uint8_t *) ao_lisp_poly_atom(atom->next) - ao_lisp_const) : 0); for (;;) { struct ao_lisp_atom *next; - atom->val = ao_lisp_poly_move(atom->val); next = ao_lisp_poly_atom(atom->next); next = ao_lisp_move_memory(next, atom_size(next)); if (!next) break; + DBG("\t\tatom move %s %d->%d\n", next->name, ((uint8_t *) ao_lisp_poly_atom(atom->next) - ao_lisp_const), ((uint8_t *) next - ao_lisp_const)); atom->next = ao_lisp_atom_poly(next); atom = next; } + DBG("\tatom move end\n"); } const struct ao_lisp_type ao_lisp_atom_type = { @@ -73,7 +86,6 @@ struct ao_lisp_atom * ao_lisp_atom_intern(char *name) { struct ao_lisp_atom *atom; -// int b; for (atom = ao_lisp_atoms; atom; atom = ao_lisp_poly_atom(atom->next)) { if (!strcmp(atom->name, name)) @@ -85,19 +97,46 @@ ao_lisp_atom_intern(char *name) return atom; } #endif - if (!ao_lisp_atoms) - ao_lisp_root_add(&ao_lisp_atom_type, (void **) &ao_lisp_atoms); atom = ao_lisp_alloc(name_size(name)); if (atom) { atom->type = AO_LISP_ATOM; atom->next = ao_lisp_atom_poly(ao_lisp_atoms); + if (!ao_lisp_atoms) + ao_lisp_root_add(&ao_lisp_atom_type, &ao_lisp_atoms); ao_lisp_atoms = atom; strcpy(atom->name, name); - atom->val = AO_LISP_NIL; } return atom; } +static struct ao_lisp_frame *globals; + +ao_poly +ao_lisp_atom_get(ao_poly atom) +{ + struct ao_lisp_frame *frame = globals; +#ifdef ao_builtin_frame + if (!frame) + frame = ao_lisp_poly_frame(ao_builtin_frame); +#endif + return ao_lisp_frame_get(frame, atom); +} + +ao_poly +ao_lisp_atom_set(ao_poly atom, ao_poly val) +{ + if (!ao_lisp_frame_set(globals, atom, val)) { + globals = ao_lisp_frame_add(globals, atom, val); + if (!globals->next) { + ao_lisp_root_add(&ao_lisp_frame_type, &globals); +#ifdef ao_builtin_frame + globals->next = ao_builtin_frame; +#endif + } + } + return val; +} + void ao_lisp_atom_print(ao_poly a) { diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index 63fb69fd..8c481793 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -14,6 +14,31 @@ #include "ao_lisp.h" +static int +builtin_size(void *addr) +{ + (void) addr; + return sizeof (struct ao_lisp_builtin); +} + +static void +builtin_mark(void *addr) +{ + (void) addr; +} + +static void +builtin_move(void *addr) +{ + (void) addr; +} + +const struct ao_lisp_type ao_lisp_builtin_type = { + .size = builtin_size, + .mark = builtin_mark, + .move = builtin_move +}; + void ao_lisp_builtin_print(ao_poly b) { @@ -120,20 +145,12 @@ ao_lisp_quote(struct ao_lisp_cons *cons) ao_poly ao_lisp_set(struct ao_lisp_cons *cons) { - ao_poly atom, val; if (!check_argc(cons, 2, 2)) return AO_LISP_NIL; if (!check_argt(cons, 0, AO_LISP_ATOM, 0)) return AO_LISP_NIL; - atom = cons->car; - val = ao_lisp_poly_cons(cons->cdr)->car; - if (ao_lisp_is_const(atom)) { - ao_lisp_exception |= AO_LISP_INVALID; - return AO_LISP_NIL; - } - ao_lisp_poly_atom(atom)->val = val; - return val; + return ao_lisp_atom_set(cons->car, ao_lisp_poly_cons(cons->cdr)->car); } ao_poly @@ -157,6 +174,8 @@ ao_lisp_print(struct ao_lisp_cons *cons) val = cons->car; ao_lisp_poly_print(val); cons = ao_lisp_poly_cons(cons->cdr); + if (cons) + printf(" "); } return val; } diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c index 65908e30..f8a34ed4 100644 --- a/src/lisp/ao_lisp_cons.c +++ b/src/lisp/ao_lisp_cons.c @@ -14,6 +14,23 @@ #include "ao_lisp.h" +#define OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_const)) + +#if 0 +static int cons_depth; +#define DBG(...) do { int d; for (d = 0; d < cons_depth; d++) printf (" "); printf(__VA_ARGS__); } while(0) +#define DBG_IN() (cons_depth++) +#define DBG_OUT() (cons_depth--) +#define DBG_PR(c) ao_lisp_cons_print(ao_lisp_cons_poly(c)) +#define DBG_PRP(p) ao_lisp_poly_print(p) +#else +#define DBG(...) +#define DBG_IN() +#define DBG_OUT() +#define DBG_PR(c) +#define DBG_PRP(p) +#endif + static void cons_mark(void *addr) { struct ao_lisp_cons *cons = addr; @@ -38,17 +55,25 @@ static void cons_move(void *addr) { struct ao_lisp_cons *cons = addr; + DBG_IN(); + DBG("move cons start %d\n", OFFSET(cons)); for (;;) { struct ao_lisp_cons *cdr; + ao_poly car; - cons->car = ao_lisp_poly_move(cons->car); + car = ao_lisp_poly_move(cons->car); + DBG(" moved car %d -> %d\n", OFFSET(ao_lisp_ref(cons->car)), OFFSET(ao_lisp_ref(car))); + cons->car = car; cdr = ao_lisp_poly_cons(cons->cdr); cdr = ao_lisp_move_memory(cdr, sizeof (struct ao_lisp_cons)); if (!cdr) break; + DBG(" moved cdr %d -> %d\n", OFFSET(ao_lisp_poly_cons(cons->cdr)), OFFSET(cdr)); cons->cdr = ao_lisp_cons_poly(cdr); cons = cdr; } + DBG("move cons end\n"); + DBG_OUT(); } const struct ao_lisp_type ao_lisp_cons_type = { diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index 2374fdb2..6eef1f23 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -91,7 +91,7 @@ ao_lisp_eval(ao_poly v) case AO_LISP_STRING: break; case AO_LISP_ATOM: - v = ao_lisp_poly_atom(v)->val; + v = ao_lisp_atom_get(v); break; } @@ -187,6 +187,9 @@ ao_lisp_eval(ao_poly v) DBG("stack pop: actuals"); DBG_CONS(actuals); DBG("\n"); DBG("stack pop: formals"); DBG_CONS(formals); DBG("\n"); } else { + actuals = 0; + formals = 0; + formals_tail = 0; DBG("done func\n"); break; } diff --git a/src/lisp/ao_lisp_frame.c b/src/lisp/ao_lisp_frame.c new file mode 100644 index 00000000..5aa50f6b --- /dev/null +++ b/src/lisp/ao_lisp_frame.c @@ -0,0 +1,191 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" + +#if 0 +#define DBG(...) printf(__VA_ARGS__) +#else +#define DBG(...) +#endif + +static inline int +frame_num_size(int num) +{ + return sizeof (struct ao_lisp_frame) + num * sizeof (struct ao_lisp_val); +} + +static int +frame_size(void *addr) +{ + struct ao_lisp_frame *frame = addr; + return frame_num_size(frame->num); +} + +#define OFFSET(a) ((uint8_t *) (ao_lisp_ref(a)) - ao_lisp_const) + +static void +frame_mark(void *addr) +{ + struct ao_lisp_frame *frame = addr; + int f; + + for (;;) { + if (frame->readonly) + break; + for (f = 0; f < frame->num; f++) { + struct ao_lisp_val *v = &frame->vals[f]; + + ao_lisp_poly_mark(v->atom); + ao_lisp_poly_mark(v->val); + DBG ("\tframe mark atom %s %d val %d at %d\n", ao_lisp_poly_atom(v->atom)->name, OFFSET(v->atom), OFFSET(v->val), f); + } + frame = ao_lisp_poly_frame(frame->next); + if (!frame) + break; + if (ao_lisp_mark_memory(frame, frame_size(frame))) + break; + } +} + +static void +frame_move(void *addr) +{ + struct ao_lisp_frame *frame = addr; + int f; + + for (;;) { + struct ao_lisp_frame *next; + if (frame->readonly) + break; + for (f = 0; f < frame->num; f++) { + struct ao_lisp_val *v = &frame->vals[f]; + ao_poly t; + + t = ao_lisp_poly_move(v->atom); + DBG("\t\tatom %s %d -> %d\n", ao_lisp_poly_atom(t)->name, OFFSET(v->atom), OFFSET(t)); + v->atom = t; + t = ao_lisp_poly_move(v->val); + DBG("\t\tval %d -> %d\n", OFFSET(v->val), OFFSET(t)); + v->val = t; + } + next = ao_lisp_poly_frame(frame->next); + if (!next) + break; + next = ao_lisp_move_memory(next, frame_size(next)); + frame->next = ao_lisp_frame_poly(next); + frame = next; + } +} + +const struct ao_lisp_type ao_lisp_frame_type = { + .mark = frame_mark, + .size = frame_size, + .move = frame_move +}; + +static ao_poly * +ao_lisp_frame_ref(struct ao_lisp_frame *frame, ao_poly atom) +{ + int f; + for (f = 0; f < frame->num; f++) + if (frame->vals[f].atom == atom) + return &frame->vals[f].val; + return NULL; +} + +int +ao_lisp_frame_set(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val) +{ + while (frame) { + if (!frame->readonly) { + ao_poly *ref = ao_lisp_frame_ref(frame, atom); + if (ref) { + *ref = val; + return 1; + } + } + frame = ao_lisp_poly_frame(frame->next); + } + return 0; +} + +ao_poly +ao_lisp_frame_get(struct ao_lisp_frame *frame, ao_poly atom) +{ + while (frame) { + ao_poly *ref = ao_lisp_frame_ref(frame, atom); + if (ref) + return *ref; + frame = ao_lisp_poly_frame(frame->next); + } + return AO_LISP_NIL; +} + +struct ao_lisp_frame * +ao_lisp_frame_new(int num, int readonly) +{ + struct ao_lisp_frame *frame = ao_lisp_alloc(frame_num_size(num)); + + if (!frame) + return NULL; + frame->num = num; + frame->readonly = readonly; + frame->next = AO_LISP_NIL; + memset(frame->vals, '\0', num * sizeof (struct ao_lisp_val)); + return frame; +} + +static struct ao_lisp_frame * +ao_lisp_frame_realloc(struct ao_lisp_frame *frame, int new_num, int readonly) +{ + struct ao_lisp_frame *new; + int copy; + + if (new_num == frame->num) + return frame; + new = ao_lisp_frame_new(new_num, readonly); + if (!new) + return NULL; + copy = new_num; + if (copy > frame->num) + copy = frame->num; + memcpy(new->vals, frame->vals, copy * sizeof (struct ao_lisp_val)); + if (frame) + new->next = frame->next; + return new; +} + +struct ao_lisp_frame * +ao_lisp_frame_add(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val) +{ + ao_poly *ref = frame ? ao_lisp_frame_ref(frame, atom) : NULL; + if (!ref) { + int f; + if (frame) { + f = frame->num; + frame = ao_lisp_frame_realloc(frame, f + 1, frame->readonly); + } else { + f = 0; + frame = ao_lisp_frame_new(1, 0); + } + if (!frame) + return NULL; + DBG ("add atom %s %d, val %d at %d\n", ao_lisp_poly_atom(atom)->name, OFFSET(atom), OFFSET(val), f); + frame->vals[f].atom = atom; + ref = &frame->vals[f].val; + } + *ref = val; + return frame; +} diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index 8d3e03a9..6b603979 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -49,19 +49,43 @@ struct builtin_func funcs[] = { #define N_FUNC (sizeof funcs / sizeof funcs[0]) +struct ao_lisp_frame *globals; + +static int +is_atom(int offset) +{ + struct ao_lisp_atom *a; + + for (a = ao_lisp_atoms; a; a = ao_lisp_poly_atom(a->next)) + if (((uint8_t *) a->name - ao_lisp_const) == offset) + return strlen(a->name); + return 0; +} + int main(int argc, char **argv) { int f, o; ao_poly atom, val; struct ao_lisp_atom *a; + int in_atom; + printf("/*\n"); + printf(" * Generated file, do not edit\n"); + ao_lisp_root_add(&ao_lisp_frame_type, &globals); + globals = ao_lisp_frame_new(0, 0); for (f = 0; f < N_FUNC; f++) { struct ao_lisp_builtin *b = ao_lisp_make_builtin(funcs[f].func, funcs[f].args); struct ao_lisp_atom *a = ao_lisp_atom_intern(funcs[f].name); - a->val = ao_lisp_builtin_poly(b); + globals = ao_lisp_frame_add(globals, ao_lisp_atom_poly(a), ao_lisp_builtin_poly(b)); } + /* boolean constants */ + a = ao_lisp_atom_intern("nil"); + globals = ao_lisp_frame_add(globals, ao_lisp_atom_poly(a), AO_LISP_NIL); + a = ao_lisp_atom_intern("t"); + globals = ao_lisp_frame_add(globals, ao_lisp_atom_poly(a), ao_lisp_atom_poly(a)); + for (;;) { atom = ao_lisp_read(); if (!atom) @@ -73,13 +97,19 @@ main(int argc, char **argv) fprintf(stderr, "input must be atom val pairs\n"); exit(1); } - ao_lisp_poly_atom(atom)->val = val; + globals = ao_lisp_frame_add(globals, atom, val); } - printf("/* constant objects, all referenced from atoms */\n\n"); + /* Reduce to referenced values */ + ao_lisp_collect(); + printf(" */\n"); + + globals->readonly = 1; + printf("#define AO_LISP_POOL_CONST %d\n", ao_lisp_top); printf("extern const uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4)));\n"); printf("#define ao_builtin_atoms 0x%04x\n", ao_lisp_atom_poly(ao_lisp_atoms)); + printf("#define ao_builtin_frame 0x%04x\n", ao_lisp_frame_poly(globals)); for (a = ao_lisp_atoms; a; a = ao_lisp_poly_atom(a->next)) { char *n = a->name, c; @@ -101,10 +131,14 @@ main(int argc, char **argv) else printf(" "); c = ao_lisp_const[o]; - if (' ' < c && c <= '~' && c != '\'') + if (!in_atom) + in_atom = is_atom(o); + if (in_atom) { printf (" '%c',", c); - else + in_atom--; + } else { printf("0x%02x,", c); + } } printf("\n};\n"); printf("#endif /* AO_LISP_CONST_BITS */\n"); diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 7295d150..27f5b666 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -17,11 +17,32 @@ #include "ao_lisp.h" #include -uint8_t ao_lisp_pool[AO_LISP_POOL] __attribute__((aligned(4))); - #ifdef AO_LISP_MAKE_CONST #include uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4))); +#define ao_lisp_pool ao_lisp_const +#undef AO_LISP_POOL +#define AO_LISP_POOL AO_LISP_POOL_CONST +#else +uint8_t ao_lisp_pool[AO_LISP_POOL] __attribute__((aligned(4))); +#endif + +#if 0 +#define DBG_DUMP +#define DBG_OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_pool)) +#define DBG(...) printf(__VA_ARGS__) +static int move_dump; +static int move_depth; +#define DBG_RESET() (move_depth = 0) +#define DBG_MOVE(...) do { if(move_dump) { int d; for (d = 0; d < move_depth; d++) printf (" "); printf(__VA_ARGS__); } } while (0) +#define DBG_MOVE_IN() (move_depth++) +#define DBG_MOVE_OUT() (move_depth--) +#else +#define DBG(...) +#define DBG_RESET() +#define DBG_MOVE(...) +#define DBG_MOVE_IN() +#define DBG_MOVE_OUT() #endif uint8_t ao_lisp_exception; @@ -112,6 +133,23 @@ clear_object(uint8_t *tag, void *addr, int size) { return 0; } +static int +busy_object(uint8_t *tag, void *addr) { + int base; + + if (!addr) + return 1; + + if ((uint8_t *) addr < ao_lisp_pool || ao_lisp_pool + AO_LISP_POOL <= (uint8_t*) addr) + return 1; + + base = (uint8_t *) addr - ao_lisp_pool; + base = limit(base); + if (busy(tag, base)) + return 1; + return 0; +} + static void *move_old, *move_new; static int move_size; @@ -120,53 +158,96 @@ move_object(void) { int i; + DBG_RESET(); + DBG_MOVE("move %d -> %d\n", DBG_OFFSET(move_old), DBG_OFFSET(move_new)); + DBG_MOVE_IN(); memset(ao_lisp_moving, '\0', sizeof (ao_lisp_moving)); for (i = 0; i < AO_LISP_ROOT; i++) - if (ao_lisp_root[i].addr) { + if (ao_lisp_root[i].addr && *ao_lisp_root[i].addr) { void *new; + DBG_MOVE("root %d\n", DBG_OFFSET(*ao_lisp_root[i].addr)); new = ao_lisp_move(ao_lisp_root[i].type, *ao_lisp_root[i].addr); if (new) *ao_lisp_root[i].addr = new; } + DBG_MOVE_OUT(); + DBG_MOVE("move done\n"); } +#ifdef DBG_DUMP static void -collect(void) +dump_busy(void) +{ + int i; + printf("busy:"); + for (i = 0; i < ao_lisp_top; i += 4) { + if ((i & 0xff) == 0) + printf("\n"); + else if ((i & 0x1f) == 0) + printf(" "); + if (busy(ao_lisp_busy, i)) + putchar('*'); + else + putchar('-'); + } + printf ("\n"); +} +#define DUMP_BUSY() dump_busy() +#else +#define DUMP_BUSY() +#endif + +void +ao_lisp_collect(void) { int i; + int top; /* Mark */ memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy)); + DBG("mark\n"); for (i = 0; i < AO_LISP_ROOT; i++) - if (ao_lisp_root[i].addr) + if (ao_lisp_root[i].addr && *ao_lisp_root[i].addr) { + DBG("root %p\n", *ao_lisp_root[i].addr); ao_lisp_mark(ao_lisp_root[i].type, *ao_lisp_root[i].addr); + } + DUMP_BUSY(); /* Compact */ - ao_lisp_top = 0; - for (i = 0; i < AO_LISP_POOL; i += 4) { + DBG("find first busy\n"); + for (i = 0; i < ao_lisp_top; i += 4) { if (!busy(ao_lisp_busy, i)) break; } - ao_lisp_top = i; - while(i < AO_LISP_POOL) { + top = i; + while(i < ao_lisp_top) { if (busy(ao_lisp_busy, i)) { + DBG("busy %d -> %d\n", i, top); move_old = &ao_lisp_pool[i]; - move_new = &ao_lisp_pool[ao_lisp_top]; + move_new = &ao_lisp_pool[top]; move_size = 0; move_object(); + DBG("\tbusy size %d\n", move_size); + if (move_size == 0) + abort(); clear_object(ao_lisp_busy, move_old, move_size); + mark_object(ao_lisp_busy, move_new, move_size); i += move_size; - ao_lisp_top += move_size; + top += move_size; + DUMP_BUSY(); } else { i += 4; } } + ao_lisp_top = top; } void ao_lisp_mark(const struct ao_lisp_type *type, void *addr) { + if (!addr) + return; if (mark_object(ao_lisp_busy, addr, type->size(addr))) return; type->mark(addr); @@ -178,12 +259,32 @@ ao_lisp_mark_memory(void *addr, int size) return mark_object(ao_lisp_busy, addr, size); } +/* + * After the object has been moved, we have to reference it + * in the new location. This is only relevant for ao_lisp_poly_move + * as it needs to fetch the type byte from the object, which + * may have been overwritten by the copy + */ +void * +ao_lisp_move_map(void *addr) +{ + if (addr == move_old) { + if (busy_object(ao_lisp_moving, addr)) + return move_new; + } + return addr; +} + static void * check_move(void *addr, int size) { if (addr == move_old) { - memmove(move_new, move_old, size); - move_size = (size + 3) & ~3; + DBG_MOVE("mapping %d -> %d\n", DBG_OFFSET(addr), DBG_OFFSET(move_new)); + if (!busy_object(ao_lisp_moving, addr)) { + DBG_MOVE(" copy %d\n", size); + memmove(move_new, move_old, size); + move_size = (size + 3) & ~3; + } addr = move_new; } return addr; @@ -192,15 +293,32 @@ check_move(void *addr, int size) void * ao_lisp_move(const struct ao_lisp_type *type, void *addr) { + uint8_t *a = addr; int size = type->size(addr); if (!addr) return NULL; +#ifndef AO_LISP_MAKE_CONST + if (AO_LISP_IS_CONST(addr)) + return addr; +#endif + DBG_MOVE("object %d\n", DBG_OFFSET(addr)); + if (a < ao_lisp_pool || ao_lisp_pool + AO_LISP_POOL <= a) + abort(); + DBG_MOVE_IN(); addr = check_move(addr, size); - if (mark_object(ao_lisp_moving, addr, size)) + if (mark_object(ao_lisp_moving, addr, size)) { + DBG_MOVE("already moved\n"); + DBG_MOVE_OUT(); return addr; + } + DBG_MOVE_OUT(); + DBG_MOVE("recursing...\n"); + DBG_MOVE_IN(); type->move(addr); + DBG_MOVE_OUT(); + DBG_MOVE("done %d\n", DBG_OFFSET(addr)); return addr; } @@ -210,9 +328,15 @@ ao_lisp_move_memory(void *addr, int size) if (!addr) return NULL; + DBG_MOVE("memory %d\n", DBG_OFFSET(addr)); + DBG_MOVE_IN(); addr = check_move(addr, size); - if (mark_object(ao_lisp_moving, addr, size)) - return NULL; + if (mark_object(ao_lisp_moving, addr, size)) { + DBG_MOVE("already moved\n"); + DBG_MOVE_OUT(); + return addr; + } + DBG_MOVE_OUT(); return addr; } @@ -222,22 +346,14 @@ ao_lisp_alloc(int size) void *addr; size = ao_lisp_mem_round(size); -#ifdef AO_LISP_MAKE_CONST - if (ao_lisp_top + size > AO_LISP_POOL_CONST) { - fprintf(stderr, "Too much constant data, increase AO_LISP_POOL_CONST\n"); - exit(1); - } - addr = ao_lisp_const + ao_lisp_top; -#else if (ao_lisp_top + size > AO_LISP_POOL) { - collect(); + ao_lisp_collect(); if (ao_lisp_top + size > AO_LISP_POOL) { ao_lisp_exception |= AO_LISP_OOM; return NULL; } } addr = ao_lisp_pool + ao_lisp_top; -#endif ao_lisp_top += size; return addr; } @@ -246,6 +362,7 @@ int ao_lisp_root_add(const struct ao_lisp_type *type, void *addr) { int i; + DBG("add root type %p addr %p\n", type, addr); for (i = 0; i < AO_LISP_ROOT; i++) { if (!ao_lisp_root[i].addr) { ao_lisp_root[i].addr = addr; @@ -253,6 +370,7 @@ ao_lisp_root_add(const struct ao_lisp_type *type, void *addr) return 1; } } + abort(); return 0; } diff --git a/src/lisp/ao_lisp_prim.c b/src/lisp/ao_lisp_prim.c index 38dcb961..e9367553 100644 --- a/src/lisp/ao_lisp_prim.c +++ b/src/lisp/ao_lisp_prim.c @@ -31,35 +31,32 @@ ao_lisp_poly_print(ao_poly p) return p; } +static const struct ao_lisp_type const *ao_lisp_types[AO_LISP_NUM_TYPE] = { + [AO_LISP_CONS] = &ao_lisp_cons_type, + [AO_LISP_STRING] = &ao_lisp_string_type, + [AO_LISP_ATOM] = &ao_lisp_atom_type, + [AO_LISP_BUILTIN] = &ao_lisp_builtin_type, +}; + void ao_lisp_poly_mark(ao_poly p) { - switch (ao_lisp_poly_type(p)) { - case AO_LISP_CONS: - ao_lisp_mark(&ao_lisp_cons_type, ao_lisp_poly_cons(p)); - break; - case AO_LISP_STRING: - ao_lisp_mark(&ao_lisp_string_type, ao_lisp_poly_string(p)); - break; - case AO_LISP_ATOM: - ao_lisp_mark(&ao_lisp_atom_type, ao_lisp_poly_atom(p)); - break; - } + const struct ao_lisp_type *lisp_type = ao_lisp_types[ao_lisp_poly_type(p)]; + if (lisp_type) + ao_lisp_mark(lisp_type, ao_lisp_ref(p)); } ao_poly ao_lisp_poly_move(ao_poly p) { - switch (ao_lisp_poly_type(p)) { - case AO_LISP_CONS: - p = ao_lisp_cons_poly(ao_lisp_move(&ao_lisp_cons_type, ao_lisp_poly_cons(p))); - break; - case AO_LISP_STRING: - p = ao_lisp_string_poly(ao_lisp_move(&ao_lisp_string_type, ao_lisp_poly_string(p))); - break; - case AO_LISP_ATOM: - p = ao_lisp_atom_poly(ao_lisp_move(&ao_lisp_atom_type, ao_lisp_poly_atom(p))); - break; - } + uint8_t type = p & AO_LISP_TYPE_MASK; + const struct ao_lisp_type *lisp_type; + + if (type == AO_LISP_OTHER) + type = ao_lisp_other_type(ao_lisp_move_map(ao_lisp_poly_other(p))); + + lisp_type = ao_lisp_types[type]; + if (lisp_type) + p = ao_lisp_poly(ao_lisp_move(lisp_type, ao_lisp_ref(p)), p & AO_LISP_TYPE_MASK); return p; } diff --git a/src/lisp/ao_lisp_read.c b/src/lisp/ao_lisp_read.c index 8fc134e5..bc1eb36b 100644 --- a/src/lisp/ao_lisp_read.c +++ b/src/lisp/ao_lisp_read.c @@ -188,8 +188,6 @@ lex_quoted (void) int count; c = lex_get(); -// if (jumping) -// return nil; if (c == EOF) return EOF; c &= 0x7f; @@ -218,8 +216,6 @@ lex_quoted (void) count = 1; while (count <= 3) { c = lex_get(); -// if (jumping) -// return nil; if (c == EOF) return EOF; c &= 0x7f; @@ -288,11 +284,17 @@ lex(void) if (lex_class & ENDOFFILE) return AO_LISP_NIL; -// if (jumping) -// return nil; if (lex_class & WHITE) continue; + if (lex_class & COMMENT) { + while ((c = lexc()) != '\n') { + if (lex_class & ENDOFFILE) + return AO_LISP_NIL; + } + continue; + } + if (lex_class & (BRA|KET|QUOTEC)) { add_token(c); end_token(); @@ -312,8 +314,6 @@ lex(void) if (lex_class & STRINGC) { for (;;) { c = lexc(); -// if (jumping) -// return nil; if (lex_class & (STRINGC|ENDOFFILE)) { end_token(); return STRING; @@ -349,8 +349,6 @@ lex(void) } add_token (c); c = lexc (); -// if (jumping) -// return nil; if (lex_class & (NOTNAME)) { // if (lex_class & ENDOFFILE) // clearerr (f); @@ -403,6 +401,10 @@ pop_read_stack(int cons) read_cons_tail && read_cons_tail->cdr; read_cons_tail = ao_lisp_poly_cons(read_cons_tail->cdr)) ; + } else { + read_cons = 0; + read_cons_tail = 0; + read_stack = 0; } return in_quote; } @@ -420,6 +422,7 @@ ao_lisp_read(void) ao_lisp_root_add(&ao_lisp_cons_type, &read_cons); ao_lisp_root_add(&ao_lisp_cons_type, &read_cons_tail); ao_lisp_root_add(&ao_lisp_cons_type, &read_stack); + been_here = 1; } parse_token = lex(); diff --git a/src/nucleao-32/Makefile b/src/nucleao-32/Makefile index 0df44317..1b7e0bb0 100644 --- a/src/nucleao-32/Makefile +++ b/src/nucleao-32/Makefile @@ -13,6 +13,8 @@ INC = \ ao_pins.h \ ao_product.h \ ao_task.h \ + ao_lisp.h \ + ao_lisp_const.h \ stm32f0.h \ Makefile @@ -43,6 +45,7 @@ ALTOS_SRC = \ ao_lisp_builtin.c \ ao_lisp_read.c \ ao_lisp_rep.c \ + ao_lisp_frame.c \ ao_exti_stm.c PRODUCT=Nucleo-32 diff --git a/src/test/Makefile b/src/test/Makefile index 6c51c421..bd195161 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -91,7 +91,9 @@ ao_quaternion_test: ao_quaternion_test.c ao_quaternion.h #AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o ao_lisp_lex.o ao_lisp_cons.o ao_lisp_string.o ao_lisp_atom.o ao_lisp_int.o ao_lisp_prim.o ao_lisp_eval.o ao_lisp_poly.o ao_lisp_builtin.o ao_lisp_read.o -AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o ao_lisp_cons.o ao_lisp_string.o ao_lisp_atom.o ao_lisp_int.o ao_lisp_prim.o ao_lisp_eval.o ao_lisp_poly.o ao_lisp_builtin.o ao_lisp_read.o ao_lisp_rep.o +AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o ao_lisp_cons.o ao_lisp_string.o \ + ao_lisp_atom.o ao_lisp_int.o ao_lisp_prim.o ao_lisp_eval.o ao_lisp_poly.o \ + ao_lisp_builtin.o ao_lisp_read.o ao_lisp_rep.o ao_lisp_frame.o ao_lisp_test: $(AO_LISP_OBJS) cc $(CFLAGS) -o $@ $(AO_LISP_OBJS) diff --git a/src/test/ao_lisp_test.c b/src/test/ao_lisp_test.c index 810a1528..e303869f 100644 --- a/src/test/ao_lisp_test.c +++ b/src/test/ao_lisp_test.c @@ -36,7 +36,6 @@ main (int argc, char **argv) list = ao_lisp_cons_cons(ao_lisp_string_poly(string), list); list = ao_lisp_cons_cons(ao_lisp_int_poly(i), list); atom = ao_lisp_atom_intern("ant"); - atom->val = ao_lisp_cons_poly(list); list = ao_lisp_cons_cons(ao_lisp_atom_poly(atom), list); } ao_lisp_poly_print(ao_lisp_cons_poly(list)); @@ -45,7 +44,7 @@ main (int argc, char **argv) for (atom = ao_lisp_poly_atom(ao_builtin_atoms); atom; atom = ao_lisp_poly_atom(atom->next)) { printf("%s = ", atom->name); - ao_lisp_poly_print(atom->val); + ao_lisp_poly_print(ao_lisp_atom_get(ao_lisp_atom_poly(atom))); printf("\n"); } #if 1 -- cgit v1.2.3 From 77db0e8162cd01c2b42737b3d71b38cea942484f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 3 Nov 2016 21:49:50 -0700 Subject: altos: Add lambda support to lisp Signed-off-by: Keith Packard --- src/lisp/Makefile | 3 +- src/lisp/ao_lisp.h | 51 ++++-- src/lisp/ao_lisp_atom.c | 62 +++++-- src/lisp/ao_lisp_builtin.c | 123 +++++++------- src/lisp/ao_lisp_const.lisp | 3 + src/lisp/ao_lisp_error.c | 29 ++++ src/lisp/ao_lisp_eval.c | 368 +++++++++++++++++++++++++++++++++++------- src/lisp/ao_lisp_frame.c | 2 +- src/lisp/ao_lisp_make_const.c | 29 +++- src/lisp/ao_lisp_rep.c | 6 - src/nucleao-32/Makefile | 1 + src/nucleao-32/ao_pins.h | 2 + src/test/Makefile | 3 +- src/test/ao_lisp_test.c | 11 +- 14 files changed, 528 insertions(+), 165 deletions(-) create mode 100644 src/lisp/ao_lisp_error.c (limited to 'src') diff --git a/src/lisp/Makefile b/src/lisp/Makefile index 9e2fb58c..be19b432 100644 --- a/src/lisp/Makefile +++ b/src/lisp/Makefile @@ -17,7 +17,8 @@ SRCS=\ ao_lisp_prim.c \ ao_lisp_builtin.c \ ao_lisp_read.c \ - ao_lisp_frame.c + ao_lisp_frame.c \ + ao_lisp_error.c OBJS=$(SRCS:.c=.o) diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 98e99acb..9a5cc63e 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -32,11 +32,22 @@ extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST]; #define ao_lisp_pool ao_lisp_const #define AO_LISP_POOL AO_LISP_POOL_CONST -#define _ao_lisp_atom_quote ao_lisp_atom_poly(ao_lisp_atom_intern("quote")) -#define _ao_lisp_atom_set ao_lisp_atom_poly(ao_lisp_atom_intern("set")) + +#define _atom(n) ao_lisp_atom_poly(ao_lisp_atom_intern(n)) + +#define _ao_lisp_atom_quote _atom("quote") +#define _ao_lisp_atom_set _atom("set") +#define _ao_lisp_atom_setq _atom("setq") +#define _ao_lisp_atom_t _atom("t") +#define _ao_lisp_atom_car _atom("car") +#define _ao_lisp_atom_cdr _atom("cdr") +#define _ao_lisp_atom_cons _atom("cons") +#define _ao_lisp_atom_cond _atom("cond") #else #include "ao_lisp_const.h" +#ifndef AO_LISP_POOL #define AO_LISP_POOL 1024 +#endif extern uint8_t ao_lisp_pool[AO_LISP_POOL]; #endif @@ -68,6 +79,7 @@ extern uint16_t ao_lisp_top; extern uint8_t ao_lisp_exception; typedef uint16_t ao_poly; +typedef int16_t ao_signed_poly; static inline int ao_lisp_is_const(ao_poly poly) { @@ -157,6 +169,7 @@ enum ao_lisp_builtin_id { builtin_quote, builtin_set, builtin_setq, + builtin_cond, builtin_print, builtin_plus, builtin_minus, @@ -222,13 +235,13 @@ ao_lisp_cons_poly(struct ao_lisp_cons *cons) static inline int ao_lisp_poly_int(ao_poly poly) { - return (int) poly >> AO_LISP_TYPE_SHIFT; + return (int) ((ao_signed_poly) poly >> AO_LISP_TYPE_SHIFT); } static inline ao_poly ao_lisp_int_poly(int i) { - return ((ao_poly) i << 2) + AO_LISP_INT; + return ((ao_poly) i << 2) | AO_LISP_INT; } static inline char * @@ -326,8 +339,7 @@ extern const struct ao_lisp_type ao_lisp_atom_type; extern struct ao_lisp_atom *ao_lisp_atoms; -void -ao_lisp_atom_init(void); +extern struct ao_lisp_frame *ao_lisp_frame_current; void ao_lisp_atom_print(ao_poly a); @@ -359,12 +371,27 @@ ao_lisp_poly_move(ao_poly p); ao_poly ao_lisp_eval(ao_poly p); +ao_poly +ao_lisp_set_cond(struct ao_lisp_cons *cons); + /* builtin */ void ao_lisp_builtin_print(ao_poly b); extern const struct ao_lisp_type ao_lisp_builtin_type; +/* Check argument count */ +ao_poly +ao_lisp_check_argc(ao_poly name, struct ao_lisp_cons *cons, int min, int max); + +/* Check argument type */ +ao_poly +ao_lisp_check_argt(ao_poly name, struct ao_lisp_cons *cons, int argc, int type, int nil_ok); + +/* Fetch an arg (nil if off the end) */ +ao_poly +ao_lisp_arg(struct ao_lisp_cons *cons, int argc); + /* read */ ao_poly ao_lisp_read(void); @@ -376,11 +403,8 @@ ao_lisp_read_eval_print(void); /* frame */ extern const struct ao_lisp_type ao_lisp_frame_type; -int -ao_lisp_frame_set(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val); - -ao_poly -ao_lisp_frame_get(struct ao_lisp_frame *frame, ao_poly atom); +ao_poly * +ao_lisp_frame_ref(struct ao_lisp_frame *frame, ao_poly atom); struct ao_lisp_frame * ao_lisp_frame_new(int num, int readonly); @@ -388,4 +412,9 @@ ao_lisp_frame_new(int num, int readonly); struct ao_lisp_frame * ao_lisp_frame_add(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val); +/* error */ + +ao_poly +ao_lisp_error(int error, char *format, ...); + #endif /* _AO_LISP_H_ */ diff --git a/src/lisp/ao_lisp_atom.c b/src/lisp/ao_lisp_atom.c index e5d28c3b..ea04741e 100644 --- a/src/lisp/ao_lisp_atom.c +++ b/src/lisp/ao_lisp_atom.c @@ -109,31 +109,65 @@ ao_lisp_atom_intern(char *name) return atom; } -static struct ao_lisp_frame *globals; +static struct ao_lisp_frame *ao_lisp_frame_global; +struct ao_lisp_frame *ao_lisp_frame_current; + +static void +ao_lisp_atom_init(void) +{ + if (!ao_lisp_frame_global) { + ao_lisp_frame_global = ao_lisp_frame_new(0, 0); + ao_lisp_root_add(&ao_lisp_frame_type, &ao_lisp_frame_global); + ao_lisp_root_add(&ao_lisp_frame_type, &ao_lisp_frame_current); + } +} + +static ao_poly * +ao_lisp_atom_ref(struct ao_lisp_frame *frame, ao_poly atom) +{ + ao_poly *ref; + ao_lisp_atom_init(); + while (frame) { + ref = ao_lisp_frame_ref(frame, atom); + if (ref) + return ref; + frame = ao_lisp_poly_frame(frame->next); + } + if (ao_lisp_frame_global) { + ref = ao_lisp_frame_ref(ao_lisp_frame_global, atom); + if (ref) + return ref; + } + return NULL; +} ao_poly ao_lisp_atom_get(ao_poly atom) { - struct ao_lisp_frame *frame = globals; + ao_poly *ref = ao_lisp_atom_ref(ao_lisp_frame_current, atom); + + if (!ref && ao_lisp_frame_global) + ref = ao_lisp_frame_ref(ao_lisp_frame_global, atom); #ifdef ao_builtin_frame - if (!frame) - frame = ao_lisp_poly_frame(ao_builtin_frame); + if (!ref) + ref = ao_lisp_frame_ref(ao_lisp_poly_frame(ao_builtin_frame), atom); #endif - return ao_lisp_frame_get(frame, atom); + if (ref) + return *ref; + return AO_LISP_NIL; } ao_poly ao_lisp_atom_set(ao_poly atom, ao_poly val) { - if (!ao_lisp_frame_set(globals, atom, val)) { - globals = ao_lisp_frame_add(globals, atom, val); - if (!globals->next) { - ao_lisp_root_add(&ao_lisp_frame_type, &globals); -#ifdef ao_builtin_frame - globals->next = ao_builtin_frame; -#endif - } - } + ao_poly *ref = ao_lisp_atom_ref(ao_lisp_frame_current, atom); + + if (!ref && ao_lisp_frame_global) + ref = ao_lisp_frame_ref(ao_lisp_frame_global, atom); + if (ref) + *ref = val; + else + ao_lisp_frame_global = ao_lisp_frame_add(ao_lisp_frame_global, atom, val); return val; } diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index 8c481793..2976bc95 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -46,7 +46,8 @@ ao_lisp_builtin_print(ao_poly b) printf("[builtin]"); } -static int check_argc(struct ao_lisp_cons *cons, int min, int max) +ao_poly +ao_lisp_check_argc(ao_poly name, struct ao_lisp_cons *cons, int min, int max) { int argc = 0; @@ -54,28 +55,30 @@ static int check_argc(struct ao_lisp_cons *cons, int min, int max) argc++; cons = ao_lisp_poly_cons(cons->cdr); } - if (argc < min || argc > max) { - ao_lisp_exception |= AO_LISP_INVALID; - return 0; - } - return 1; + if (argc < min || argc > max) + return ao_lisp_error(AO_LISP_INVALID, "%s: invalid arg count", ao_lisp_poly_atom(name)->name); + return _ao_lisp_atom_t; } -static int check_argt(struct ao_lisp_cons *cons, int argc, int type, int nil_ok) +ao_poly +ao_lisp_arg(struct ao_lisp_cons *cons, int argc) { - ao_poly car; - - /* find the desired arg */ - while (argc--) + while (argc--) { + if (!cons) + return AO_LISP_NIL; cons = ao_lisp_poly_cons(cons->cdr); - car = cons->car; - if ((!car && !nil_ok) || - ao_lisp_poly_type(car) != type) - { - ao_lisp_exception |= AO_LISP_INVALID; - return 0; } - return 1; + return cons->car; +} + +ao_poly +ao_lisp_check_argt(ao_poly name, struct ao_lisp_cons *cons, int argc, int type, int nil_ok) +{ + ao_poly car = ao_lisp_arg(cons, argc); + + if ((!car && !nil_ok) || ao_lisp_poly_type(car) != type) + return ao_lisp_error(AO_LISP_INVALID, "%s: invalid type for arg %d", ao_lisp_poly_atom(name)->name, argc); + return _ao_lisp_atom_t; } enum math_op { math_plus, math_minus, math_times, math_divide, math_mod }; @@ -83,30 +86,20 @@ enum math_op { math_plus, math_minus, math_times, math_divide, math_mod }; ao_poly ao_lisp_car(struct ao_lisp_cons *cons) { - if (!check_argc(cons, 1, 1)) + if (!ao_lisp_check_argc(_ao_lisp_atom_car, cons, 1, 1)) return AO_LISP_NIL; - if (!check_argt(cons, 0, AO_LISP_CONS, 0)) { - ao_lisp_exception |= AO_LISP_INVALID; + if (!ao_lisp_check_argt(_ao_lisp_atom_car, cons, 0, AO_LISP_CONS, 0)) return AO_LISP_NIL; - } return ao_lisp_poly_cons(cons->car)->car; } ao_poly ao_lisp_cdr(struct ao_lisp_cons *cons) { - if (!cons) { - ao_lisp_exception |= AO_LISP_INVALID; + if (!ao_lisp_check_argc(_ao_lisp_atom_cdr, cons, 1, 1)) return AO_LISP_NIL; - } - if (!cons->car) { - ao_lisp_exception |= AO_LISP_INVALID; - return AO_LISP_NIL; - } - if (ao_lisp_poly_type(cons->car) != AO_LISP_CONS) { - ao_lisp_exception |= AO_LISP_INVALID; + if (!ao_lisp_check_argt(_ao_lisp_atom_cdr, cons, 0, AO_LISP_CONS, 0)) return AO_LISP_NIL; - } return ao_lisp_poly_cons(cons->car)->cdr; } @@ -114,50 +107,39 @@ ao_poly ao_lisp_cons(struct ao_lisp_cons *cons) { ao_poly car, cdr; - if (!cons) { - ao_lisp_exception |= AO_LISP_INVALID; - return AO_LISP_NIL; - } - car = cons->car; - cdr = cons->cdr; - if (!car || !cdr) { - ao_lisp_exception |= AO_LISP_INVALID; + if(!ao_lisp_check_argc(_ao_lisp_atom_cons, cons, 2, 2)) return AO_LISP_NIL; - } - cdr = ao_lisp_poly_cons(cdr)->car; - if (ao_lisp_poly_type(cdr) != AO_LISP_CONS) { - ao_lisp_exception |= AO_LISP_INVALID; + if (!ao_lisp_check_argt(_ao_lisp_atom_cons, cons, 1, AO_LISP_CONS, 1)) return AO_LISP_NIL; - } + car = ao_lisp_arg(cons, 0); + cdr = ao_lisp_arg(cons, 1); return ao_lisp_cons_poly(ao_lisp_cons_cons(car, ao_lisp_poly_cons(cdr))); } ao_poly ao_lisp_quote(struct ao_lisp_cons *cons) { - if (!cons) { - ao_lisp_exception |= AO_LISP_INVALID; + if (!ao_lisp_check_argc(_ao_lisp_atom_quote, cons, 1, 1)) return AO_LISP_NIL; - } - return cons->car; + return ao_lisp_arg(cons, 0); } ao_poly ao_lisp_set(struct ao_lisp_cons *cons) { - if (!check_argc(cons, 2, 2)) + if (!ao_lisp_check_argc(_ao_lisp_atom_set, cons, 2, 2)) return AO_LISP_NIL; - if (!check_argt(cons, 0, AO_LISP_ATOM, 0)) + if (!ao_lisp_check_argt(_ao_lisp_atom_set, cons, 0, AO_LISP_ATOM, 0)) return AO_LISP_NIL; - return ao_lisp_atom_set(cons->car, ao_lisp_poly_cons(cons->cdr)->car); + return ao_lisp_atom_set(ao_lisp_arg(cons, 0), ao_lisp_poly_cons(ao_lisp_arg(cons, 1))->car); } ao_poly ao_lisp_setq(struct ao_lisp_cons *cons) { struct ao_lisp_cons *expand = 0; - if (!check_argc(cons, 2, 2)) + if (!ao_lisp_check_argc(_ao_lisp_atom_setq, cons, 2, 2)) return AO_LISP_NIL; expand = ao_lisp_cons_cons(_ao_lisp_atom_set, ao_lisp_cons_cons(ao_lisp_cons_poly(ao_lisp_cons_cons(_ao_lisp_atom_quote, @@ -166,6 +148,22 @@ ao_lisp_setq(struct ao_lisp_cons *cons) return ao_lisp_cons_poly(expand); } +ao_poly +ao_lisp_cond(struct ao_lisp_cons *cons) +{ + int argc; + struct ao_lisp_cons *arg; + + argc = 0; + for (arg = cons, argc = 0; arg; arg = ao_lisp_poly_cons(arg->cdr), argc++) { + if (ao_lisp_poly_type(arg->car) != AO_LISP_CONS) + return ao_lisp_error(AO_LISP_INVALID, "%s: invalid type for arg %d", + ao_lisp_poly_atom(_ao_lisp_atom_cond)->name, argc); + } + ao_lisp_set_cond(cons); + return AO_LISP_NIL; +} + ao_poly ao_lisp_print(struct ao_lisp_cons *cons) { @@ -210,17 +208,13 @@ ao_lisp_math(struct ao_lisp_cons *cons, enum math_op op) r *= c; break; case math_divide: - if (c == 0) { - ao_lisp_exception |= AO_LISP_DIVIDE_BY_ZERO; - return AO_LISP_NIL; - } + if (c == 0) + return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "divide by zero"); r /= c; break; case math_mod: - if (c == 0) { - ao_lisp_exception |= AO_LISP_DIVIDE_BY_ZERO; - return AO_LISP_NIL; - } + if (c == 0) + return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "mod by zero"); r %= c; break; } @@ -230,10 +224,8 @@ ao_lisp_math(struct ao_lisp_cons *cons, enum math_op op) else if (rt == AO_LISP_STRING && ct == AO_LISP_STRING && op == math_plus) ret = ao_lisp_string_poly(ao_lisp_string_cat(ao_lisp_poly_string(ret), ao_lisp_poly_string(car))); - else { - ao_lisp_exception |= AO_LISP_INVALID; - return AO_LISP_NIL; - } + else + return ao_lisp_error(AO_LISP_INVALID, "invalid args"); } return ret; } @@ -275,6 +267,7 @@ ao_lisp_func_t ao_lisp_builtins[] = { [builtin_quote] = ao_lisp_quote, [builtin_set] = ao_lisp_set, [builtin_setq] = ao_lisp_setq, + [builtin_cond] = ao_lisp_cond, [builtin_print] = ao_lisp_print, [builtin_plus] = ao_lisp_plus, [builtin_minus] = ao_lisp_minus, diff --git a/src/lisp/ao_lisp_const.lisp b/src/lisp/ao_lisp_const.lisp index aa356d45..5ee15899 100644 --- a/src/lisp/ao_lisp_const.lisp +++ b/src/lisp/ao_lisp_const.lisp @@ -1 +1,4 @@ cadr (lambda (l) (car (cdr l))) +list (lexpr (l) l) +1+ (lambda (x) (+ x 1)) +1- (lambda (x) (- x 1)) diff --git a/src/lisp/ao_lisp_error.c b/src/lisp/ao_lisp_error.c new file mode 100644 index 00000000..ea8111d9 --- /dev/null +++ b/src/lisp/ao_lisp_error.c @@ -0,0 +1,29 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao_lisp.h" +#include + +ao_poly +ao_lisp_error(int error, char *format, ...) +{ + va_list args; + + ao_lisp_exception |= error; + va_start(args, format); + vprintf(format, args); + va_end(args); + printf("\n"); + return AO_LISP_NIL; +} diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index 6eef1f23..803f1e2e 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -14,32 +14,238 @@ #include "ao_lisp.h" -/* - * Non-recursive eval - * - * Plan: walk actuals, construct formals - * - * stack > save > actuals > actual_1 - * v v - * formals . > actual_2 - */ - -static struct ao_lisp_cons *stack; -static struct ao_lisp_cons *actuals; -static struct ao_lisp_cons *formals; -static struct ao_lisp_cons *formals_tail; -static uint8_t been_here; - #if 0 #define DBG(...) printf(__VA_ARGS__) -#define DBG_CONS(a) ao_lisp_cons_print(a) +#define DBG_CONS(a) ao_lisp_cons_print(ao_lisp_cons_poly(a)) #define DBG_POLY(a) ao_lisp_poly_print(a) +#define OFFSET(a) ((a) ? (int) ((uint8_t *) a - ao_lisp_pool) : -1) #else #define DBG(...) #define DBG_CONS(a) #define DBG_POLY(a) #endif +struct ao_lisp_stack { + ao_poly next; + ao_poly actuals; + ao_poly formals; + ao_poly frame; + ao_poly cond; +}; + +static struct ao_lisp_stack * +ao_lisp_poly_stack(ao_poly p) +{ + return ao_lisp_ref(p); +} + +static ao_poly +ao_lisp_stack_poly(struct ao_lisp_stack *stack) +{ + return ao_lisp_poly(stack, AO_LISP_OTHER); +} + +static int +stack_size(void *addr) +{ + (void) addr; + return sizeof (struct ao_lisp_stack); +} + +static void +stack_mark(void *addr) +{ + struct ao_lisp_stack *stack = addr; + for (;;) { + ao_lisp_poly_mark(stack->actuals); + ao_lisp_poly_mark(stack->formals); + ao_lisp_poly_mark(stack->frame); + ao_lisp_poly_mark(stack->cond); + stack = ao_lisp_poly_stack(stack->next); + if (ao_lisp_mark_memory(stack, sizeof (struct ao_lisp_stack))) + break; + } +} + +static void +stack_move(void *addr) +{ + struct ao_lisp_stack *stack = addr; + + for (;;) { + struct ao_lisp_stack *next; + stack->actuals = ao_lisp_poly_move(stack->actuals); + stack->formals = ao_lisp_poly_move(stack->formals); + stack->frame = ao_lisp_poly_move(stack->frame); + stack->cond = ao_lisp_poly_move(stack->cond); + next = ao_lisp_ref(stack->next); + next = ao_lisp_move_memory(next, sizeof (struct ao_lisp_stack)); + stack->next = ao_lisp_stack_poly(next); + stack = next; + } +} + +static const struct ao_lisp_type ao_lisp_stack_type = { + .size = stack_size, + .mark = stack_mark, + .move = stack_move +}; + + +static struct ao_lisp_stack *stack; +static struct ao_lisp_cons *actuals; +static struct ao_lisp_cons *formals; +static struct ao_lisp_cons *formals_tail; +static struct ao_lisp_cons *cond; +struct ao_lisp_frame *next_frame; +static uint8_t been_here; + +ao_poly +ao_lisp_set_cond(struct ao_lisp_cons *c) +{ + cond = c; + return AO_LISP_NIL; +} + +static int +ao_lisp_stack_push(void) +{ + struct ao_lisp_stack *n = ao_lisp_alloc(sizeof (struct ao_lisp_stack)); + if (!n) + return 0; + n->next = ao_lisp_stack_poly(stack); + n->actuals = ao_lisp_cons_poly(actuals); + n->formals = ao_lisp_cons_poly(formals); + n->cond = ao_lisp_cons_poly(cond); + n->frame = ao_lisp_frame_poly(ao_lisp_frame_current); + DBG("push frame %d\n", OFFSET(ao_lisp_frame_current)); + stack = n; + return 1; +} + +static void +ao_lisp_stack_pop(void) +{ + actuals = ao_lisp_poly_cons(stack->actuals); + formals = ao_lisp_poly_cons(stack->formals); + cond = ao_lisp_poly_cons(stack->cond); + ao_lisp_frame_current = ao_lisp_poly_frame(stack->frame); + DBG("pop frame %d\n", OFFSET(ao_lisp_frame_current)); + formals_tail = 0; + + /* Recompute the tail of the formals list */ + if (formals) { + struct ao_lisp_cons *formal; + for (formal = formals; formal->cdr != AO_LISP_NIL; formal = ao_lisp_poly_cons(formal->cdr)); + formals_tail = formal; + } + stack = ao_lisp_poly_stack(stack->next); +} + +static void +ao_lisp_stack_clear(void) +{ + stack = 0; + actuals = formals = formals_tail = 0; + cond = 0; + ao_lisp_frame_current = 0; +} + + +static ao_poly +func_type(ao_poly func) +{ + struct ao_lisp_cons *cons; + struct ao_lisp_cons *args; + int f; + + DBG("func type "); DBG_POLY(func); DBG("\n"); + if (func == AO_LISP_NIL) + return ao_lisp_error(AO_LISP_INVALID, "func is nil"); + if (ao_lisp_poly_type(func) != AO_LISP_CONS) + return ao_lisp_error(AO_LISP_INVALID, "func is not list"); + cons = ao_lisp_poly_cons(func); + if (!ao_lisp_check_argc(_ao_lisp_atom_lambda, cons, 3, 3)) + return AO_LISP_NIL; + if (!ao_lisp_check_argt(_ao_lisp_atom_lambda, cons, 0, AO_LISP_ATOM, 0)) + return AO_LISP_NIL; + if (!ao_lisp_check_argt(_ao_lisp_atom_lambda, cons, 1, AO_LISP_CONS, 1)) + return AO_LISP_NIL; + args = ao_lisp_poly_cons(ao_lisp_arg(cons, 1)); + f = 0; + while (args) { + if (ao_lisp_poly_type(args->car) != AO_LISP_ATOM) { + return ao_lisp_error(ao_lisp_arg(cons, 0), "formal %d is not an atom", f); + } + args = ao_lisp_poly_cons(args->cdr); + f++; + } + return ao_lisp_arg(cons, 0); +} + +static int +ao_lisp_cons_length(struct ao_lisp_cons *cons) +{ + int len = 0; + while (cons) { + len++; + cons = ao_lisp_poly_cons(cons->cdr); + } + return len; +} + +static ao_poly +ao_lisp_lambda(struct ao_lisp_cons *cons) +{ + ao_poly type; + struct ao_lisp_cons *lambda; + struct ao_lisp_cons *args; + int args_wanted; + int args_provided; + + lambda = ao_lisp_poly_cons(ao_lisp_arg(cons, 0)); + DBG("lambda "); DBG_CONS(lambda); DBG("\n"); + type = ao_lisp_arg(lambda, 0); + args = ao_lisp_poly_cons(ao_lisp_arg(lambda, 1)); + + args_wanted = ao_lisp_cons_length(args); + + /* Create a frame to hold the variables + */ + if (type == _ao_lisp_atom_lambda) + args_provided = ao_lisp_cons_length(cons) - 1; + else + args_provided = 1; + if (args_wanted != args_provided) + return ao_lisp_error(AO_LISP_INVALID, "need %d args, not %d", args_wanted, args_provided); + next_frame = ao_lisp_frame_new(args_wanted, 0); + DBG("new frame %d\n", OFFSET(next_frame)); + switch (type) { + case _ao_lisp_atom_lambda: { + int f; + struct ao_lisp_cons *vals = ao_lisp_poly_cons(cons->cdr); + + for (f = 0; f < args_wanted; f++) { + next_frame->vals[f].atom = args->car; + next_frame->vals[f].val = vals->car; + args = ao_lisp_poly_cons(args->cdr); + vals = ao_lisp_poly_cons(vals->cdr); + } + break; + } + case _ao_lisp_atom_lexpr: + case _ao_lisp_atom_nlambda: + next_frame->vals[0].atom = args->car; + next_frame->vals[0].val = cons->cdr; + break; + case _ao_lisp_atom_macro: + next_frame->vals[0].atom = args->car; + next_frame->vals[0].val = ao_lisp_cons_poly(cons); + break; + } + return ao_lisp_arg(lambda, 2); +} + ao_poly ao_lisp_eval(ao_poly v) { @@ -48,7 +254,7 @@ ao_lisp_eval(ao_poly v) if (!been_here) { been_here = 1; - ao_lisp_root_add(&ao_lisp_cons_type, &stack); + ao_lisp_root_add(&ao_lisp_stack_type, &stack); ao_lisp_root_add(&ao_lisp_cons_type, &actuals); ao_lisp_root_add(&ao_lisp_cons_type, &formals); ao_lisp_root_add(&ao_lisp_cons_type, &formals_tail); @@ -57,29 +263,43 @@ ao_lisp_eval(ao_poly v) actuals = 0; formals = 0; formals_tail = 0; + cond = 0; for (;;) { restart: + if (cond) { + if (cond->car == AO_LISP_NIL) { + cond = AO_LISP_NIL; + v = AO_LISP_NIL; + } else { + if (ao_lisp_poly_type(cond->car) != AO_LISP_CONS) { + ao_lisp_error(AO_LISP_INVALID, "malformed cond"); + goto bail; + } + v = ao_lisp_poly_cons(cond->car)->car; + } + } + /* Build stack frames for each list */ while (ao_lisp_poly_type(v) == AO_LISP_CONS) { if (v == AO_LISP_NIL) break; - /* Push existing frame on the stack */ - if (cons++) { - struct ao_lisp_cons *frame; + /* Push existing bits on the stack */ + if (cons++) + if (!ao_lisp_stack_push()) + goto bail; - frame = ao_lisp_cons_cons(ao_lisp_cons_poly(actuals), formals); - stack = ao_lisp_cons_cons(ao_lisp_cons_poly(frame), stack); - } actuals = ao_lisp_poly_cons(v); formals = NULL; formals_tail = NULL; + cond = NULL; + v = actuals->car; - DBG("start: stack"); DBG_CONS(stack); DBG("\n"); - DBG("start: actuals"); DBG_CONS(actuals); DBG("\n"); - DBG("start: formals"); DBG_CONS(formals); DBG("\n"); +// DBG("start: stack"); DBG_CONS(stack); DBG("\n"); +// DBG("start: actuals"); DBG_CONS(actuals); DBG("\n"); +// DBG("start: formals"); DBG_CONS(formals); DBG("\n"); } /* Evaluate primitive types */ @@ -95,19 +315,19 @@ ao_lisp_eval(ao_poly v) break; } - if (!cons) - break; - - for (;;) { + while (cons) { DBG("add formal: "); DBG_POLY(v); DBG("\n"); + /* We've processed the first element of the list, go check + * what kind of function we've got + */ if (formals == NULL) { if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) { struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v); switch (b->args) { case AO_LISP_NLAMBDA: - v = ao_lisp_func(b)(ao_lisp_poly_cons(actuals->cdr)); - goto done_eval; + formals = actuals; + goto eval; case AO_LISP_MACRO: v = ao_lisp_func(b)(ao_lisp_poly_cons(actuals->cdr)); @@ -115,15 +335,28 @@ ao_lisp_eval(ao_poly v) DBG(" -> "); DBG_POLY(v); DBG("\n"); if (ao_lisp_poly_type(v) != AO_LISP_CONS) { - ao_lisp_exception |= AO_LISP_INVALID; - return AO_LISP_NIL; + ao_lisp_error(AO_LISP_INVALID, "macro didn't return list"); + goto bail; } - /* Reset frame to the new list */ actuals = ao_lisp_poly_cons(v); v = actuals->car; goto restart; } + } else { + switch (func_type(v)) { + case _ao_lisp_atom_lambda: + case _ao_lisp_atom_lexpr: + break; + case _ao_lisp_atom_nlambda: + formals = actuals; + goto eval; + case _ao_lisp_atom_macro: + break; + default: + ao_lisp_error(AO_LISP_INVALID, "operator is not a function"); + goto bail; + } } } @@ -150,6 +383,8 @@ ao_lisp_eval(ao_poly v) v = formals->car; + eval: + /* Evaluate the resulting list */ if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) { struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v); @@ -161,41 +396,54 @@ ao_lisp_eval(ao_poly v) DBG(" -> "); DBG_POLY(v); DBG ("\n"); + if (ao_lisp_exception) + goto bail; + + if (cond) + goto restart; } else { - ao_lisp_exception |= AO_LISP_INVALID; + v = ao_lisp_lambda(formals); + if (ao_lisp_exception) + goto bail; } - if (ao_lisp_exception) - return AO_LISP_NIL; - done_eval: - if (--cons) { - struct ao_lisp_cons *frame; - - /* Pop the previous frame off the stack */ - frame = ao_lisp_poly_cons(stack->car); - actuals = ao_lisp_poly_cons(frame->car); - formals = ao_lisp_poly_cons(frame->cdr); - formals_tail = NULL; - - /* Recompute the tail of the formals list */ - if (formals) { - for (formal = formals; formal->cdr != AO_LISP_NIL; formal = ao_lisp_poly_cons(formal->cdr)); - formals_tail = formal; - } - stack = ao_lisp_poly_cons(stack->cdr); - DBG("stack pop: stack"); DBG_CONS(stack); DBG("\n"); - DBG("stack pop: actuals"); DBG_CONS(actuals); DBG("\n"); - DBG("stack pop: formals"); DBG_CONS(formals); DBG("\n"); + --cons; + if (cons) { + ao_lisp_stack_pop(); +// DBG("stack pop: stack"); DBG_CONS(stack); DBG("\n"); +// DBG("stack pop: actuals"); DBG_CONS(actuals); DBG("\n"); +// DBG("stack pop: formals"); DBG_CONS(formals); DBG("\n"); } else { actuals = 0; formals = 0; formals_tail = 0; - DBG("done func\n"); - break; + ao_lisp_frame_current = 0; + } + if (next_frame) { + ao_lisp_frame_current = next_frame; + DBG("next frame %d\n", OFFSET(next_frame)); + next_frame = 0; + goto restart; + } + if (cond) { + if (v) { + v = ao_lisp_poly_cons(cond->car)->cdr; + if (v != AO_LISP_NIL) { + v = ao_lisp_poly_cons(v)->car; + goto restart; + } + } else { + cond = ao_lisp_poly_cons(cond->cdr); + goto restart; + } } } if (!cons) break; } + DBG("leaving frame at %d\n", OFFSET(ao_lisp_frame_current)); return v; +bail: + ao_lisp_stack_clear(); + return AO_LISP_NIL; } diff --git a/src/lisp/ao_lisp_frame.c b/src/lisp/ao_lisp_frame.c index 5aa50f6b..1853f6d7 100644 --- a/src/lisp/ao_lisp_frame.c +++ b/src/lisp/ao_lisp_frame.c @@ -95,7 +95,7 @@ const struct ao_lisp_type ao_lisp_frame_type = { .move = frame_move }; -static ao_poly * +ao_poly * ao_lisp_frame_ref(struct ao_lisp_frame *frame, ao_poly atom) { int f; diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index 6b603979..9c2ea74c 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -39,6 +39,7 @@ struct builtin_func funcs[] = { "quote", AO_LISP_NLAMBDA,builtin_quote, "set", AO_LISP_LEXPR, builtin_set, "setq", AO_LISP_MACRO, builtin_setq, + "cond", AO_LISP_NLAMBDA,builtin_cond, "print", AO_LISP_LEXPR, builtin_print, "+", AO_LISP_LEXPR, builtin_plus, "-", AO_LISP_LEXPR, builtin_minus, @@ -47,8 +48,25 @@ struct builtin_func funcs[] = { "%", AO_LISP_LEXPR, builtin_mod }; +ao_poly +ao_lisp_set_cond(struct ao_lisp_cons *c) +{ + (void) c; + return AO_LISP_NIL; +} + #define N_FUNC (sizeof funcs / sizeof funcs[0]) +/* Syntactic atoms */ +char *atoms[] = { + "lambda", + "nlambda", + "lexpr", + "macro" +}; + +#define N_ATOM (sizeof atoms / sizeof atoms[0]) + struct ao_lisp_frame *globals; static int @@ -65,9 +83,10 @@ is_atom(int offset) int main(int argc, char **argv) { - int f, o; + int f, o, i; ao_poly atom, val; struct ao_lisp_atom *a; + struct ao_lisp_builtin *b; int in_atom; printf("/*\n"); @@ -75,11 +94,15 @@ main(int argc, char **argv) ao_lisp_root_add(&ao_lisp_frame_type, &globals); globals = ao_lisp_frame_new(0, 0); for (f = 0; f < N_FUNC; f++) { - struct ao_lisp_builtin *b = ao_lisp_make_builtin(funcs[f].func, funcs[f].args); - struct ao_lisp_atom *a = ao_lisp_atom_intern(funcs[f].name); + b = ao_lisp_make_builtin(funcs[f].func, funcs[f].args); + a = ao_lisp_atom_intern(funcs[f].name); globals = ao_lisp_frame_add(globals, ao_lisp_atom_poly(a), ao_lisp_builtin_poly(b)); } + /* atoms for syntax */ + for (i = 0; i < N_ATOM; i++) + (void) ao_lisp_atom_intern(atoms[i]); + /* boolean constants */ a = ao_lisp_atom_intern("nil"); globals = ao_lisp_frame_add(globals, ao_lisp_atom_poly(a), AO_LISP_NIL); diff --git a/src/lisp/ao_lisp_rep.c b/src/lisp/ao_lisp_rep.c index a1f9fa1f..d780186a 100644 --- a/src/lisp/ao_lisp_rep.c +++ b/src/lisp/ao_lisp_rep.c @@ -25,12 +25,6 @@ ao_lisp_read_eval_print(void) // printf ("in: "); ao_lisp_poly_print(in); printf("\n"); out = ao_lisp_eval(in); if (ao_lisp_exception) { - if (ao_lisp_exception & AO_LISP_OOM) - printf("out of memory\n"); - if (ao_lisp_exception & AO_LISP_DIVIDE_BY_ZERO) - printf("divide by zero\n"); - if (ao_lisp_exception & AO_LISP_INVALID) - printf("invalid operation\n"); ao_lisp_exception = 0; } else { ao_lisp_poly_print(out); diff --git a/src/nucleao-32/Makefile b/src/nucleao-32/Makefile index 1b7e0bb0..388e581c 100644 --- a/src/nucleao-32/Makefile +++ b/src/nucleao-32/Makefile @@ -46,6 +46,7 @@ ALTOS_SRC = \ ao_lisp_read.c \ ao_lisp_rep.c \ ao_lisp_frame.c \ + ao_lisp_error.c \ ao_exti_stm.c PRODUCT=Nucleo-32 diff --git a/src/nucleao-32/ao_pins.h b/src/nucleao-32/ao_pins.h index 76200176..65de89ed 100644 --- a/src/nucleao-32/ao_pins.h +++ b/src/nucleao-32/ao_pins.h @@ -24,6 +24,8 @@ #define LED_PIN_GREEN 3 #define AO_LED_GREEN (1 << LED_PIN_GREEN) #define AO_LED_PANIC AO_LED_GREEN +#define AO_CMD_LEN 128 +#define AO_LISP_POOL 2048 #define LEDS_AVAILABLE (AO_LED_GREEN) diff --git a/src/test/Makefile b/src/test/Makefile index bd195161..8d617eea 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -93,7 +93,8 @@ ao_quaternion_test: ao_quaternion_test.c ao_quaternion.h AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o ao_lisp_cons.o ao_lisp_string.o \ ao_lisp_atom.o ao_lisp_int.o ao_lisp_prim.o ao_lisp_eval.o ao_lisp_poly.o \ - ao_lisp_builtin.o ao_lisp_read.o ao_lisp_rep.o ao_lisp_frame.o + ao_lisp_builtin.o ao_lisp_read.o ao_lisp_rep.o ao_lisp_frame.o \ + ao_lisp_error.o ao_lisp_test: $(AO_LISP_OBJS) cc $(CFLAGS) -o $@ $(AO_LISP_OBJS) diff --git a/src/test/ao_lisp_test.c b/src/test/ao_lisp_test.c index e303869f..8bc677da 100644 --- a/src/test/ao_lisp_test.c +++ b/src/test/ao_lisp_test.c @@ -15,15 +15,18 @@ #include "ao_lisp.h" #include +#if 0 static struct ao_lisp_cons *list; static char *string; +#endif int main (int argc, char **argv) { +#if 0 int i, j; - struct ao_lisp_atom *atom; + struct ao_lisp_atom *atom; ao_lisp_root_add(&ao_lisp_cons_type, (void **) &list); ao_lisp_root_add(&ao_lisp_string_type, (void **) &string); @@ -47,7 +50,8 @@ main (int argc, char **argv) ao_lisp_poly_print(ao_lisp_atom_get(ao_lisp_atom_poly(atom))); printf("\n"); } -#if 1 +#endif +#if 0 list = ao_lisp_cons_cons(ao_lisp_atom_poly(ao_lisp_atom_intern("+")), ao_lisp_cons_cons(ao_lisp_cons_poly(ao_lisp_cons_cons(ao_lisp_atom_poly(ao_lisp_atom_intern("+")), ao_lisp_cons_cons(ao_lisp_int_poly(3), @@ -58,7 +62,8 @@ main (int argc, char **argv) printf ("\n"); ao_lisp_poly_print(ao_lisp_eval(ao_lisp_cons_poly(list))); printf ("\n"); - +#endif +#if 1 ao_lisp_read_eval_print(); #endif } -- cgit v1.2.3 From c48bda3625fc507134da7b4af87a634e8eb3715b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 3 Nov 2016 21:51:26 -0700 Subject: altos: Add lambdakey Signed-off-by: Keith Packard --- src/lambdakey-v1.0/.gitignore | 2 + src/lambdakey-v1.0/Makefile | 86 ++++++++++++++++++++++++++++++ src/lambdakey-v1.0/ao_lambdakey.c | 70 ++++++++++++++++++++++++ src/lambdakey-v1.0/ao_pins.h | 58 ++++++++++++++++++++ src/lambdakey-v1.0/flash-loader/.gitignore | 2 + src/lambdakey-v1.0/flash-loader/Makefile | 8 +++ src/lambdakey-v1.0/flash-loader/ao_pins.h | 37 +++++++++++++ 7 files changed, 263 insertions(+) create mode 100644 src/lambdakey-v1.0/.gitignore create mode 100644 src/lambdakey-v1.0/Makefile create mode 100644 src/lambdakey-v1.0/ao_lambdakey.c create mode 100644 src/lambdakey-v1.0/ao_pins.h create mode 100644 src/lambdakey-v1.0/flash-loader/.gitignore create mode 100644 src/lambdakey-v1.0/flash-loader/Makefile create mode 100644 src/lambdakey-v1.0/flash-loader/ao_pins.h (limited to 'src') diff --git a/src/lambdakey-v1.0/.gitignore b/src/lambdakey-v1.0/.gitignore new file mode 100644 index 00000000..6462d930 --- /dev/null +++ b/src/lambdakey-v1.0/.gitignore @@ -0,0 +1,2 @@ +lambdakey-* +ao_product.h diff --git a/src/lambdakey-v1.0/Makefile b/src/lambdakey-v1.0/Makefile new file mode 100644 index 00000000..4db0e290 --- /dev/null +++ b/src/lambdakey-v1.0/Makefile @@ -0,0 +1,86 @@ +# +# AltOS build +# +# + +include ../stmf0/Makefile.defs + +INC = \ + ao.h \ + ao_arch.h \ + ao_arch_funcs.h \ + ao_boot.h \ + ao_pins.h \ + ao_product.h \ + ao_task.h \ + ao_lisp.h \ + ao_lisp_const.h \ + stm32f0.h \ + Makefile + +ALTOS_SRC = \ + ao_boot_chain.c \ + ao_interrupt.c \ + ao_product.c \ + ao_romconfig.c \ + ao_cmd.c \ + ao_config.c \ + ao_task.c \ + ao_led.c \ + ao_dma_stm.c \ + ao_stdio.c \ + ao_panic.c \ + ao_timer.c \ + ao_mutex.c \ + ao_usb_stm.c \ + ao_serial_stm.c \ + ao_lisp_lex.c \ + ao_lisp_mem.c \ + ao_lisp_cons.c \ + ao_lisp_eval.c \ + ao_lisp_string.c \ + ao_lisp_atom.c \ + ao_lisp_int.c \ + ao_lisp_prim.c \ + ao_lisp_builtin.c \ + ao_lisp_read.c \ + ao_lisp_rep.c \ + ao_lisp_frame.c \ + ao_lisp_error.c \ + ao_exti_stm.c + +PRODUCT=LambdaKey-v1.0 +PRODUCT_DEF=-DLAMBDAKEY +IDPRODUCT=0x000a + +CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -Os -g + +PROGNAME=lambdakey-v1.0 +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +SRC=$(ALTOS_SRC) ao_lambdakey.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) altos.ld + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +$(OBJ): $(INC) + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +load: $(PROG) + stm-load $(PROG) + +distclean: clean + +clean: + rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx + rm -f ao_product.h + +install: + +uninstall: diff --git a/src/lambdakey-v1.0/ao_lambdakey.c b/src/lambdakey-v1.0/ao_lambdakey.c new file mode 100644 index 00000000..6ac78717 --- /dev/null +++ b/src/lambdakey-v1.0/ao_lambdakey.c @@ -0,0 +1,70 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include + +static uint16_t blink_delay, blink_running; + +static void blink(void) { + blink_running = 1; + while (blink_delay) { + ao_led_on(AO_LED_RED); + ao_delay(blink_delay); + ao_led_off(AO_LED_RED); + ao_delay(blink_delay); + } + blink_running = 0; + ao_wakeup(&blink_running); + ao_exit(); +} + +struct ao_task blink_task; + +static void blink_cmd() { + ao_cmd_decimal(); + blink_delay = ao_cmd_lex_i; + if (blink_delay && !blink_running) + ao_add_task(&blink_task, blink, "blink"); + if (!blink_delay) + while (blink_running) + ao_sleep(&blink_running); +} + +static void lisp_cmd() { + ao_lisp_read_eval_print(); +} + +static const struct ao_cmds blink_cmds[] = { + { blink_cmd, "b \0Blink the green LED" }, + { lisp_cmd, "l\0Run lisp interpreter" }, + { 0, 0 } +}; + + +void main(void) +{ + ao_led_init(LEDS_AVAILABLE); + ao_clock_init(); + ao_task_init(); + ao_timer_init(); + ao_dma_init(); + ao_usb_init(); + ao_serial_init(); + ao_cmd_init(); + ao_cmd_register(blink_cmds); + ao_start_scheduler(); +} + + diff --git a/src/lambdakey-v1.0/ao_pins.h b/src/lambdakey-v1.0/ao_pins.h new file mode 100644 index 00000000..e379ed12 --- /dev/null +++ b/src/lambdakey-v1.0/ao_pins.h @@ -0,0 +1,58 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define LED_PORT_ENABLE STM_RCC_AHBENR_IOPBEN +#define LED_PORT (&stm_gpiob) +#define LED_PIN_RED 4 +#define AO_LED_RED (1 << LED_PIN_RED) +#define AO_LED_PANIC AO_LED_RED +#define AO_CMD_LEN 128 +#define AO_LISP_POOL 2048 + +#define LEDS_AVAILABLE (AO_LED_RED) + +#define AO_POWER_MANAGEMENT 0 + +/* 48MHz clock based on USB */ +#define AO_HSI48 1 + +/* HCLK = 48MHz */ +#define AO_AHB_PRESCALER 1 +#define AO_RCC_CFGR_HPRE_DIV STM_RCC_CFGR_HPRE_DIV_1 + +/* APB = 48MHz */ +#define AO_APB_PRESCALER 1 +#define AO_RCC_CFGR_PPRE_DIV STM_RCC_CFGR_PPRE_DIV_1 + +#define HAS_USB 1 +#define AO_USB_DIRECTIO 0 +#define AO_PA11_PA12_RMP 1 +#define HAS_BEEP 0 + +#define IS_FLASH_LOADER 0 + +#define HAS_SERIAL_2 1 +#define SERIAL_2_PA2_PA15 1 +#define USE_SERIAL_2_FLOW 0 +#define USE_SERIAL_2_STDIN 1 +#define DELAY_SERIAL_2_STDIN 0 + +#endif /* _AO_PINS_H_ */ diff --git a/src/lambdakey-v1.0/flash-loader/.gitignore b/src/lambdakey-v1.0/flash-loader/.gitignore new file mode 100644 index 00000000..86ebb7f2 --- /dev/null +++ b/src/lambdakey-v1.0/flash-loader/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +lambdakey* diff --git a/src/lambdakey-v1.0/flash-loader/Makefile b/src/lambdakey-v1.0/flash-loader/Makefile new file mode 100644 index 00000000..dbded719 --- /dev/null +++ b/src/lambdakey-v1.0/flash-loader/Makefile @@ -0,0 +1,8 @@ +# +# AltOS flash loader build +# +# + +TOPDIR=../.. +HARDWARE=lambdakey-v1.0 +include $(TOPDIR)/stmf0/Makefile-flash.defs diff --git a/src/lambdakey-v1.0/flash-loader/ao_pins.h b/src/lambdakey-v1.0/flash-loader/ao_pins.h new file mode 100644 index 00000000..4b788f67 --- /dev/null +++ b/src/lambdakey-v1.0/flash-loader/ao_pins.h @@ -0,0 +1,37 @@ +/* + * Copyright © 2013 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#include + +/* Pin 5 on debug connector */ + +#define AO_BOOT_PIN 1 +#define AO_BOOT_APPLICATION_GPIO stm_gpioa +#define AO_BOOT_APPLICATION_PIN 15 +#define AO_BOOT_APPLICATION_VALUE 1 +#define AO_BOOT_APPLICATION_MODE AO_EXTI_MODE_PULL_UP + +/* USB */ +#define HAS_USB 1 +#define AO_USB_DIRECTIO 0 +#define AO_PA11_PA12_RMP 1 + +#endif /* _AO_PINS_H_ */ -- cgit v1.2.3 From c9456362c8bad8cd9be717f591f2d0841f88eb50 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 4 Nov 2016 16:31:34 -0700 Subject: altos/lisp: Start rewriting eval as state machine Ad-hoc code was incomprehensible and I couldn't make 'cond' work, so I'm starting over. Signed-off-by: Keith Packard --- src/lisp/ao_lisp_eval.c | 333 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 240 insertions(+), 93 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index 803f1e2e..5e4908ff 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -14,23 +14,40 @@ #include "ao_lisp.h" -#if 0 -#define DBG(...) printf(__VA_ARGS__) +#if 1 +static int stack_depth; +#define DBG_INDENT() do { int _s; for(_s = 0; _s < stack_depth; _s++) printf(" "); } while(0) +#define DBG_IN() (++stack_depth) +#define DBG_OUT() (--stack_depth) +#define DBG(...) printf(__VA_ARGS__) +#define DBGI(...) do { DBG_INDENT(); DBG(__VA_ARGS__); } while (0) #define DBG_CONS(a) ao_lisp_cons_print(ao_lisp_cons_poly(a)) #define DBG_POLY(a) ao_lisp_poly_print(a) #define OFFSET(a) ((a) ? (int) ((uint8_t *) a - ao_lisp_pool) : -1) #else +#define DBG_INDENT() +#define DBG_IN() +#define DBG_OUT() #define DBG(...) +#define DBGI(...) #define DBG_CONS(a) #define DBG_POLY(a) #endif +enum eval_state { + eval_sexpr, + eval_val, + eval_exec, + eval_exec_direct +}; + struct ao_lisp_stack { - ao_poly next; + ao_poly prev; + uint8_t state; ao_poly actuals; ao_poly formals; + ao_poly formals_tail; ao_poly frame; - ao_poly cond; }; static struct ao_lisp_stack * @@ -60,8 +77,7 @@ stack_mark(void *addr) ao_lisp_poly_mark(stack->actuals); ao_lisp_poly_mark(stack->formals); ao_lisp_poly_mark(stack->frame); - ao_lisp_poly_mark(stack->cond); - stack = ao_lisp_poly_stack(stack->next); + stack = ao_lisp_poly_stack(stack->prev); if (ao_lisp_mark_memory(stack, sizeof (struct ao_lisp_stack))) break; } @@ -73,15 +89,14 @@ stack_move(void *addr) struct ao_lisp_stack *stack = addr; for (;;) { - struct ao_lisp_stack *next; + struct ao_lisp_stack *prev; stack->actuals = ao_lisp_poly_move(stack->actuals); stack->formals = ao_lisp_poly_move(stack->formals); stack->frame = ao_lisp_poly_move(stack->frame); - stack->cond = ao_lisp_poly_move(stack->cond); - next = ao_lisp_ref(stack->next); - next = ao_lisp_move_memory(next, sizeof (struct ao_lisp_stack)); - stack->next = ao_lisp_stack_poly(next); - stack = next; + prev = ao_lisp_ref(stack->prev); + prev = ao_lisp_move_memory(prev, sizeof (struct ao_lisp_stack)); + stack->prev = ao_lisp_stack_poly(prev); + stack = prev; } } @@ -92,63 +107,59 @@ static const struct ao_lisp_type ao_lisp_stack_type = { }; -static struct ao_lisp_stack *stack; -static struct ao_lisp_cons *actuals; -static struct ao_lisp_cons *formals; -static struct ao_lisp_cons *formals_tail; -static struct ao_lisp_cons *cond; -struct ao_lisp_frame *next_frame; +static struct ao_lisp_stack *ao_lisp_stack; static uint8_t been_here; ao_poly ao_lisp_set_cond(struct ao_lisp_cons *c) { - cond = c; return AO_LISP_NIL; } -static int +static void +ao_lisp_stack_reset(struct ao_lisp_stack *stack) +{ + stack->state = eval_sexpr; + stack->actuals = AO_LISP_NIL; + stack->formals = AO_LISP_NIL; + stack->formals_tail = AO_LISP_NIL; + stack->frame = ao_lisp_frame_poly(ao_lisp_frame_current); +} + +static struct ao_lisp_stack * ao_lisp_stack_push(void) { - struct ao_lisp_stack *n = ao_lisp_alloc(sizeof (struct ao_lisp_stack)); - if (!n) - return 0; - n->next = ao_lisp_stack_poly(stack); - n->actuals = ao_lisp_cons_poly(actuals); - n->formals = ao_lisp_cons_poly(formals); - n->cond = ao_lisp_cons_poly(cond); - n->frame = ao_lisp_frame_poly(ao_lisp_frame_current); - DBG("push frame %d\n", OFFSET(ao_lisp_frame_current)); - stack = n; - return 1; + struct ao_lisp_stack *stack = ao_lisp_alloc(sizeof (struct ao_lisp_stack)); + if (!stack) + return NULL; + stack->prev = ao_lisp_stack_poly(ao_lisp_stack); + ao_lisp_stack_reset(stack); + ao_lisp_stack = stack; + DBGI("stack push\n"); + DBG_IN(); + return stack; } -static void +static struct ao_lisp_stack * ao_lisp_stack_pop(void) { - actuals = ao_lisp_poly_cons(stack->actuals); - formals = ao_lisp_poly_cons(stack->formals); - cond = ao_lisp_poly_cons(stack->cond); - ao_lisp_frame_current = ao_lisp_poly_frame(stack->frame); - DBG("pop frame %d\n", OFFSET(ao_lisp_frame_current)); - formals_tail = 0; - - /* Recompute the tail of the formals list */ - if (formals) { - struct ao_lisp_cons *formal; - for (formal = formals; formal->cdr != AO_LISP_NIL; formal = ao_lisp_poly_cons(formal->cdr)); - formals_tail = formal; - } - stack = ao_lisp_poly_stack(stack->next); + if (!ao_lisp_stack) + return NULL; + DBG_OUT(); + DBGI("stack pop\n"); + ao_lisp_stack = ao_lisp_poly_stack(ao_lisp_stack->prev); + if (ao_lisp_stack) + ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->frame); + else + ao_lisp_frame_current = NULL; + return ao_lisp_stack; } static void ao_lisp_stack_clear(void) { - stack = 0; - actuals = formals = formals_tail = 0; - cond = 0; - ao_lisp_frame_current = 0; + ao_lisp_stack = NULL; + ao_lisp_frame_current = NULL; } @@ -159,28 +170,32 @@ func_type(ao_poly func) struct ao_lisp_cons *args; int f; - DBG("func type "); DBG_POLY(func); DBG("\n"); + DBGI("func type "); DBG_POLY(func); DBG("\n"); if (func == AO_LISP_NIL) return ao_lisp_error(AO_LISP_INVALID, "func is nil"); - if (ao_lisp_poly_type(func) != AO_LISP_CONS) - return ao_lisp_error(AO_LISP_INVALID, "func is not list"); - cons = ao_lisp_poly_cons(func); - if (!ao_lisp_check_argc(_ao_lisp_atom_lambda, cons, 3, 3)) - return AO_LISP_NIL; - if (!ao_lisp_check_argt(_ao_lisp_atom_lambda, cons, 0, AO_LISP_ATOM, 0)) - return AO_LISP_NIL; - if (!ao_lisp_check_argt(_ao_lisp_atom_lambda, cons, 1, AO_LISP_CONS, 1)) - return AO_LISP_NIL; - args = ao_lisp_poly_cons(ao_lisp_arg(cons, 1)); - f = 0; - while (args) { - if (ao_lisp_poly_type(args->car) != AO_LISP_ATOM) { - return ao_lisp_error(ao_lisp_arg(cons, 0), "formal %d is not an atom", f); + if (ao_lisp_poly_type(func) == AO_LISP_BUILTIN) { + struct ao_lisp_builtin *b = ao_lisp_poly_builtin(func); + return b->args; + } else if (ao_lisp_poly_type(func) == AO_LISP_CONS) { + cons = ao_lisp_poly_cons(func); + if (!ao_lisp_check_argc(_ao_lisp_atom_lambda, cons, 3, 3)) + return AO_LISP_NIL; + if (!ao_lisp_check_argt(_ao_lisp_atom_lambda, cons, 0, AO_LISP_ATOM, 0)) + return AO_LISP_NIL; + if (!ao_lisp_check_argt(_ao_lisp_atom_lambda, cons, 1, AO_LISP_CONS, 1)) + return AO_LISP_NIL; + args = ao_lisp_poly_cons(ao_lisp_arg(cons, 1)); + f = 0; + while (args) { + if (ao_lisp_poly_type(args->car) != AO_LISP_ATOM) { + return ao_lisp_error(ao_lisp_arg(cons, 0), "formal %d is not an atom", f); + } + args = ao_lisp_poly_cons(args->cdr); + f++; } - args = ao_lisp_poly_cons(args->cdr); - f++; - } - return ao_lisp_arg(cons, 0); + return ao_lisp_arg(cons, 0); + } else + return ao_lisp_error(AO_LISP_INVALID, "not a func"); } static int @@ -200,11 +215,12 @@ ao_lisp_lambda(struct ao_lisp_cons *cons) ao_poly type; struct ao_lisp_cons *lambda; struct ao_lisp_cons *args; + struct ao_lisp_frame *next_frame; int args_wanted; int args_provided; lambda = ao_lisp_poly_cons(ao_lisp_arg(cons, 0)); - DBG("lambda "); DBG_CONS(lambda); DBG("\n"); + DBGI("lambda "); DBG_CONS(lambda); DBG("\n"); type = ao_lisp_arg(lambda, 0); args = ao_lisp_poly_cons(ao_lisp_arg(lambda, 1)); @@ -219,7 +235,7 @@ ao_lisp_lambda(struct ao_lisp_cons *cons) if (args_wanted != args_provided) return ao_lisp_error(AO_LISP_INVALID, "need %d args, not %d", args_wanted, args_provided); next_frame = ao_lisp_frame_new(args_wanted, 0); - DBG("new frame %d\n", OFFSET(next_frame)); + DBGI("new frame %d\n", OFFSET(next_frame)); switch (type) { case _ao_lisp_atom_lambda: { int f; @@ -243,31 +259,125 @@ ao_lisp_lambda(struct ao_lisp_cons *cons) next_frame->vals[0].val = ao_lisp_cons_poly(cons); break; } + next_frame->next = ao_lisp_frame_poly(ao_lisp_frame_current); + ao_lisp_frame_current = next_frame; + ao_lisp_stack->frame = ao_lisp_frame_poly(next_frame); return ao_lisp_arg(lambda, 2); } ao_poly ao_lisp_eval(ao_poly v) { - struct ao_lisp_cons *formal; - int cons = 0; + struct ao_lisp_stack *stack; + ao_poly formal; if (!been_here) { been_here = 1; ao_lisp_root_add(&ao_lisp_stack_type, &stack); - ao_lisp_root_add(&ao_lisp_cons_type, &actuals); - ao_lisp_root_add(&ao_lisp_cons_type, &formals); - ao_lisp_root_add(&ao_lisp_cons_type, &formals_tail); } - stack = 0; - actuals = 0; - formals = 0; - formals_tail = 0; - cond = 0; + + stack = ao_lisp_stack_push(); + for (;;) { + if (ao_lisp_exception) + return AO_LISP_NIL; + switch (stack->state) { + case eval_sexpr: + DBGI("sexpr: "); DBG_POLY(v); DBG("\n"); + switch (ao_lisp_poly_type(v)) { + case AO_LISP_CONS: + if (v == AO_LISP_NIL) { + stack->state = eval_exec; + break; + } + stack->actuals = v; + stack = ao_lisp_stack_push(); + v = ao_lisp_poly_cons(v)->car; + break; + case AO_LISP_ATOM: + v = ao_lisp_atom_get(v); + /* fall through */ + case AO_LISP_INT: + case AO_LISP_STRING: + stack->state = eval_val; + break; + } + break; + case eval_val: + DBGI("val: "); DBG_POLY(v); DBG("\n"); + stack = ao_lisp_stack_pop(); + if (!stack) + return v; + + stack->state = eval_sexpr; + /* Check what kind of function we've got */ + if (!stack->formals) { + switch (func_type(v)) { + case AO_LISP_LAMBDA: + case _ao_lisp_atom_lambda: + case AO_LISP_LEXPR: + case _ao_lisp_atom_lexpr: + DBGI(".. lambda or lexpr\n"); + break; + case AO_LISP_NLAMBDA: + case _ao_lisp_atom_nlambda: + case AO_LISP_MACRO: + case _ao_lisp_atom_macro: + DBGI(".. nlambda or macro\n"); + stack->formals = stack->actuals; + stack->state = eval_exec_direct; + break; + } + if (stack->state == eval_exec_direct) + break; + } + + formal = ao_lisp_cons_poly(ao_lisp_cons_cons(v, NULL)); + if (!formal) { + ao_lisp_stack_clear(); + return AO_LISP_NIL; + } + + if (stack->formals_tail) + ao_lisp_poly_cons(stack->formals_tail)->cdr = formal; + else + stack->formals = formal; + stack->formals_tail = formal; + + DBGI("formals now "); DBG_POLY(stack->formals); DBG("\n"); + + v = ao_lisp_poly_cons(stack->actuals)->cdr; + + break; + case eval_exec: + v = ao_lisp_poly_cons(stack->formals)->car; + case eval_exec_direct: + DBGI("exec: "); DBG_POLY(v); DBG(" formals "); DBG_POLY(stack->formals); DBG ("\n"); + if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) { + struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v); + + v = ao_lisp_func(b) (ao_lisp_poly_cons(ao_lisp_poly_cons(stack->formals)->cdr)); + DBGI("builtin result:"); DBG_POLY(v); DBG ("\n"); + if (ao_lisp_exception) { + ao_lisp_stack_clear(); + return AO_LISP_NIL; + } + stack->state = eval_val; + break; + } else { + v = ao_lisp_lambda(ao_lisp_poly_cons(stack->formals)); + ao_lisp_stack_reset(stack); + } + break; + } + } +} +#if 0 + restart: if (cond) { + DBGI("cond is now "); DBG_CONS(cond); DBG("\n"); if (cond->car == AO_LISP_NIL) { cond = AO_LISP_NIL; v = AO_LISP_NIL; @@ -293,6 +403,7 @@ ao_lisp_eval(ao_poly v) actuals = ao_lisp_poly_cons(v); formals = NULL; formals_tail = NULL; + save_cond = cond; cond = NULL; v = actuals->car; @@ -302,6 +413,27 @@ ao_lisp_eval(ao_poly v) // DBG("start: formals"); DBG_CONS(formals); DBG("\n"); } + if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) { + struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v); + switch (b->args) { + case AO_LISP_NLAMBDA: + formals = actuals; + goto eval; + + case AO_LISP_MACRO: + v = ao_lisp_func(b)(ao_lisp_poly_cons(actuals->cdr)); + DBG("macro "); DBG_POLY(ao_lisp_cons_poly(actuals)); + DBG(" -> "); DBG_POLY(v); + DBG("\n"); + if (ao_lisp_poly_type(v) != AO_LISP_CONS) { + ao_lisp_error(AO_LISP_INVALID, "macro didn't return list"); + goto bail; + } + /* Reset frame to the new list */ + actuals = ao_lisp_poly_cons(v); + v = actuals->car; + goto restart; + } /* Evaluate primitive types */ DBG ("actual: "); DBG_POLY(v); DBG("\n"); @@ -387,6 +519,7 @@ ao_lisp_eval(ao_poly v) /* Evaluate the resulting list */ if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) { + struct ao_lisp_cons *old_cond = cond; struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v); v = ao_lisp_func(b) (ao_lisp_poly_cons(formals->cdr)); @@ -399,14 +532,22 @@ ao_lisp_eval(ao_poly v) if (ao_lisp_exception) goto bail; - if (cond) + if (cond != old_cond) { + DBG("cond changed from "); DBG_CONS(old_cond); DBG(" to "); DBG_CONS(cond); DBG("\n"); + actuals = NULL; + formals = 0; + formals_tail = 0; + save_cons = cons; + cons = 0; goto restart; + } } else { v = ao_lisp_lambda(formals); if (ao_lisp_exception) goto bail; } + cond_done: --cons; if (cons) { ao_lisp_stack_pop(); @@ -425,17 +566,22 @@ ao_lisp_eval(ao_poly v) next_frame = 0; goto restart; } - if (cond) { - if (v) { - v = ao_lisp_poly_cons(cond->car)->cdr; - if (v != AO_LISP_NIL) { - v = ao_lisp_poly_cons(v)->car; - goto restart; - } - } else { - cond = ao_lisp_poly_cons(cond->cdr); - goto restart; + } + if (cond) { + DBG("next cond cons is %d\n", cons); + if (v) { + v = ao_lisp_poly_cons(cond->car)->cdr; + cond = 0; + cons = save_cons; + if (v != AO_LISP_NIL) { + v = ao_lisp_poly_cons(v)->car; + DBG("cond complete, sexpr is "); DBG_POLY(v); DBG("\n"); } + goto cond_done; + } else { + cond = ao_lisp_poly_cons(cond->cdr); + DBG("next cond is "); DBG_CONS(cond); DBG("\n"); + goto restart; } } if (!cons) @@ -446,4 +592,5 @@ ao_lisp_eval(ao_poly v) bail: ao_lisp_stack_clear(); return AO_LISP_NIL; -} +#endif + -- cgit v1.2.3 From 6fc1ee0f7adc6fcb3e850bcbaabc1db705314234 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 4 Nov 2016 16:51:12 -0700 Subject: altos/lisp: get builtin macros working again Signed-off-by: Keith Packard --- src/lisp/ao_lisp_builtin.c | 2 +- src/lisp/ao_lisp_eval.c | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index 2976bc95..fe729f20 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -132,7 +132,7 @@ ao_lisp_set(struct ao_lisp_cons *cons) if (!ao_lisp_check_argt(_ao_lisp_atom_set, cons, 0, AO_LISP_ATOM, 0)) return AO_LISP_NIL; - return ao_lisp_atom_set(ao_lisp_arg(cons, 0), ao_lisp_poly_cons(ao_lisp_arg(cons, 1))->car); + return ao_lisp_atom_set(ao_lisp_arg(cons, 0), ao_lisp_arg(cons, 1)); } ao_poly diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index 5e4908ff..2b2cfee7 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -44,6 +44,7 @@ enum eval_state { struct ao_lisp_stack { ao_poly prev; uint8_t state; + uint8_t macro; ao_poly actuals; ao_poly formals; ao_poly formals_tail; @@ -120,6 +121,7 @@ static void ao_lisp_stack_reset(struct ao_lisp_stack *stack) { stack->state = eval_sexpr; + stack->macro = 0; stack->actuals = AO_LISP_NIL; stack->formals = AO_LISP_NIL; stack->formals_tail = AO_LISP_NIL; @@ -319,10 +321,11 @@ ao_lisp_eval(ao_poly v) case _ao_lisp_atom_lexpr: DBGI(".. lambda or lexpr\n"); break; - case AO_LISP_NLAMBDA: - case _ao_lisp_atom_nlambda: case AO_LISP_MACRO: case _ao_lisp_atom_macro: + stack->macro = 1; + case AO_LISP_NLAMBDA: + case _ao_lisp_atom_nlambda: DBGI(".. nlambda or macro\n"); stack->formals = stack->actuals; stack->state = eval_exec_direct; @@ -352,17 +355,23 @@ ao_lisp_eval(ao_poly v) case eval_exec: v = ao_lisp_poly_cons(stack->formals)->car; case eval_exec_direct: - DBGI("exec: "); DBG_POLY(v); DBG(" formals "); DBG_POLY(stack->formals); DBG ("\n"); + DBGI("exec: macro %d ", stack->macro); DBG_POLY(v); DBG(" formals "); DBG_POLY(stack->formals); DBG ("\n"); if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) { struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v); + struct ao_lisp_cons *f = ao_lisp_poly_cons(ao_lisp_poly_cons(stack->formals)->cdr); - v = ao_lisp_func(b) (ao_lisp_poly_cons(ao_lisp_poly_cons(stack->formals)->cdr)); + DBGI(".. builtin formals "); DBG_CONS(f); DBG("\n"); + v = ao_lisp_func(b) (f); DBGI("builtin result:"); DBG_POLY(v); DBG ("\n"); if (ao_lisp_exception) { ao_lisp_stack_clear(); return AO_LISP_NIL; } - stack->state = eval_val; + if (stack->macro) + stack->state = eval_sexpr; + else + stack->state = eval_val; + stack->macro = 0; break; } else { v = ao_lisp_lambda(ao_lisp_poly_cons(stack->formals)); -- cgit v1.2.3 From 3366efb139653939f053c1fe4aba352ba3b66c94 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 5 Nov 2016 14:51:58 -0700 Subject: altos/lisp: Change GC move API Pass reference to move API so it can change the values in-place, then let it return '1' when the underlying object has already been moved to shorten GC times. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 38 +++-- src/lisp/ao_lisp_atom.c | 26 +--- src/lisp/ao_lisp_builtin.c | 142 +++++++++++++++-- src/lisp/ao_lisp_cons.c | 37 +---- src/lisp/ao_lisp_const.lisp | 3 + src/lisp/ao_lisp_eval.c | 349 ++++++++++++------------------------------ src/lisp/ao_lisp_frame.c | 48 +++--- src/lisp/ao_lisp_make_const.c | 11 +- src/lisp/ao_lisp_mem.c | 169 ++++++++++++++++---- src/lisp/ao_lisp_prim.c | 44 +++++- 10 files changed, 464 insertions(+), 403 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 9a5cc63e..27174e13 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -46,7 +46,7 @@ extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST]; #else #include "ao_lisp_const.h" #ifndef AO_LISP_POOL -#define AO_LISP_POOL 1024 +#define AO_LISP_POOL 16384 #endif extern uint8_t ao_lisp_pool[AO_LISP_POOL]; #endif @@ -94,6 +94,8 @@ ao_lisp_is_const(ao_poly poly) { static inline void * ao_lisp_ref(ao_poly poly) { + if (poly == 0xBEEF) + abort(); if (poly == AO_LISP_NIL) return NULL; if (poly & AO_LISP_CONST) @@ -135,8 +137,8 @@ struct ao_lisp_val { }; struct ao_lisp_frame { + uint8_t type; uint8_t num; - uint8_t readonly; ao_poly next; struct ao_lisp_val vals[]; }; @@ -176,6 +178,11 @@ enum ao_lisp_builtin_id { builtin_times, builtin_divide, builtin_mod, + builtin_equal, + builtin_less, + builtin_greater, + builtin_less_equal, + builtin_greater_equal, builtin_last }; @@ -281,7 +288,8 @@ ao_lisp_builtin_poly(struct ao_lisp_builtin *b) } /* memory functions */ -void +/* returns 1 if the object was already marked */ +int ao_lisp_mark(const struct ao_lisp_type *type, void *addr); /* returns 1 if the object was already marked */ @@ -291,12 +299,13 @@ ao_lisp_mark_memory(void *addr, int size); void * ao_lisp_move_map(void *addr); -void * -ao_lisp_move(const struct ao_lisp_type *type, void *addr); +/* returns 1 if the object was already moved */ +int +ao_lisp_move(const struct ao_lisp_type *type, void **ref); -/* returns NULL if the object was already moved */ -void * -ao_lisp_move_memory(void *addr, int size); +/* returns 1 if the object was already moved */ +int +ao_lisp_move_memory(void **ref, int size); void * ao_lisp_alloc(int size); @@ -307,6 +316,9 @@ ao_lisp_collect(void); int ao_lisp_root_add(const struct ao_lisp_type *type, void *addr); +int +ao_lisp_root_poly_add(ao_poly *p); + void ao_lisp_root_clear(void *addr); @@ -361,13 +373,15 @@ ao_lisp_int_print(ao_poly i); ao_poly ao_lisp_poly_print(ao_poly p); -void +int ao_lisp_poly_mark(ao_poly p); -ao_poly -ao_lisp_poly_move(ao_poly p); +/* returns 1 if the object has already been moved */ +int +ao_lisp_poly_move(ao_poly *p); /* eval */ + ao_poly ao_lisp_eval(ao_poly p); @@ -407,7 +421,7 @@ ao_poly * ao_lisp_frame_ref(struct ao_lisp_frame *frame, ao_poly atom); struct ao_lisp_frame * -ao_lisp_frame_new(int num, int readonly); +ao_lisp_frame_new(int num); struct ao_lisp_frame * ao_lisp_frame_add(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val); diff --git a/src/lisp/ao_lisp_atom.c b/src/lisp/ao_lisp_atom.c index ea04741e..5f1bcda0 100644 --- a/src/lisp/ao_lisp_atom.c +++ b/src/lisp/ao_lisp_atom.c @@ -17,12 +17,6 @@ #include "ao_lisp.h" -#if 0 -#define DBG(...) printf(__VA_ARGS__) -#else -#define DBG(...) -#endif - static int name_size(char *name) { return sizeof(struct ao_lisp_atom) + strlen(name) + 1; @@ -40,38 +34,24 @@ static void atom_mark(void *addr) { struct ao_lisp_atom *atom = addr; - DBG ("\tatom start %s\n", atom->name); for (;;) { atom = ao_lisp_poly_atom(atom->next); if (!atom) break; - DBG("\t\tatom mark %s %d\n", atom->name, (uint8_t *) atom - ao_lisp_const); if (ao_lisp_mark_memory(atom, atom_size(atom))) break; } - DBG ("\tatom done\n"); } static void atom_move(void *addr) { struct ao_lisp_atom *atom = addr; - DBG("\tatom move start %s %d next %s %d\n", - atom->name, ((uint8_t *) atom - ao_lisp_const), - atom->next ? ao_lisp_poly_atom(atom->next)->name : "(none)", - atom->next ? ((uint8_t *) ao_lisp_poly_atom(atom->next) - ao_lisp_const) : 0); for (;;) { - struct ao_lisp_atom *next; - - next = ao_lisp_poly_atom(atom->next); - next = ao_lisp_move_memory(next, atom_size(next)); - if (!next) + if (ao_lisp_poly_move(&atom->next)) break; - DBG("\t\tatom move %s %d->%d\n", next->name, ((uint8_t *) ao_lisp_poly_atom(atom->next) - ao_lisp_const), ((uint8_t *) next - ao_lisp_const)); - atom->next = ao_lisp_atom_poly(next); - atom = next; + atom = ao_lisp_poly_atom(atom->next); } - DBG("\tatom move end\n"); } const struct ao_lisp_type ao_lisp_atom_type = { @@ -116,7 +96,7 @@ static void ao_lisp_atom_init(void) { if (!ao_lisp_frame_global) { - ao_lisp_frame_global = ao_lisp_frame_new(0, 0); + ao_lisp_frame_global = ao_lisp_frame_new(0); ao_lisp_root_add(&ao_lisp_frame_type, &ao_lisp_frame_global); ao_lisp_root_add(&ao_lisp_frame_type, &ao_lisp_frame_current); } diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index fe729f20..0ad1f464 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -63,6 +63,8 @@ ao_lisp_check_argc(ao_poly name, struct ao_lisp_cons *cons, int min, int max) ao_poly ao_lisp_arg(struct ao_lisp_cons *cons, int argc) { + if (!cons) + return AO_LISP_NIL; while (argc--) { if (!cons) return AO_LISP_NIL; @@ -81,8 +83,6 @@ ao_lisp_check_argt(ao_poly name, struct ao_lisp_cons *cons, int argc, int type, return _ao_lisp_atom_t; } -enum math_op { math_plus, math_minus, math_times, math_divide, math_mod }; - ao_poly ao_lisp_car(struct ao_lisp_cons *cons) { @@ -175,11 +175,12 @@ ao_lisp_print(struct ao_lisp_cons *cons) if (cons) printf(" "); } + printf("\n"); return val; } ao_poly -ao_lisp_math(struct ao_lisp_cons *cons, enum math_op op) +ao_lisp_math(struct ao_lisp_cons *cons, enum ao_lisp_builtin_id op) { ao_poly ret = AO_LISP_NIL; @@ -198,30 +199,32 @@ ao_lisp_math(struct ao_lisp_cons *cons, enum math_op op) int c = ao_lisp_poly_int(car); switch(op) { - case math_plus: + case builtin_plus: r += c; break; - case math_minus: + case builtin_minus: r -= c; break; - case math_times: + case builtin_times: r *= c; break; - case math_divide: + case builtin_divide: if (c == 0) return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "divide by zero"); r /= c; break; - case math_mod: + case builtin_mod: if (c == 0) return ao_lisp_error(AO_LISP_DIVIDE_BY_ZERO, "mod by zero"); r %= c; break; + default: + break; } ret = ao_lisp_int_poly(r); } - else if (rt == AO_LISP_STRING && ct == AO_LISP_STRING && op == math_plus) + else if (rt == AO_LISP_STRING && ct == AO_LISP_STRING && op == builtin_plus) ret = ao_lisp_string_poly(ao_lisp_string_cat(ao_lisp_poly_string(ret), ao_lisp_poly_string(car))); else @@ -233,31 +236,135 @@ ao_lisp_math(struct ao_lisp_cons *cons, enum math_op op) ao_poly ao_lisp_plus(struct ao_lisp_cons *cons) { - return ao_lisp_math(cons, math_plus); + return ao_lisp_math(cons, builtin_plus); } ao_poly ao_lisp_minus(struct ao_lisp_cons *cons) { - return ao_lisp_math(cons, math_minus); + return ao_lisp_math(cons, builtin_minus); } ao_poly ao_lisp_times(struct ao_lisp_cons *cons) { - return ao_lisp_math(cons, math_times); + return ao_lisp_math(cons, builtin_times); } ao_poly ao_lisp_divide(struct ao_lisp_cons *cons) { - return ao_lisp_math(cons, math_divide); + return ao_lisp_math(cons, builtin_divide); } ao_poly ao_lisp_mod(struct ao_lisp_cons *cons) { - return ao_lisp_math(cons, math_mod); + return ao_lisp_math(cons, builtin_mod); +} + +ao_poly +ao_lisp_compare(struct ao_lisp_cons *cons, enum ao_lisp_builtin_id op) +{ + ao_poly left; + + if (!cons) + return _ao_lisp_atom_t; + + left = cons->car; + cons = ao_lisp_poly_cons(cons->cdr); + while (cons) { + ao_poly right = cons->car; + + if (op == builtin_equal) { + if (left != right) + return AO_LISP_NIL; + } else { + uint8_t lt = ao_lisp_poly_type(left); + uint8_t rt = ao_lisp_poly_type(right); + if (lt == AO_LISP_INT && rt == AO_LISP_INT) { + int l = ao_lisp_poly_int(left); + int r = ao_lisp_poly_int(right); + + switch (op) { + case builtin_less: + if (!(l < r)) + return AO_LISP_NIL; + break; + case builtin_greater: + if (!(l > r)) + return AO_LISP_NIL; + break; + case builtin_less_equal: + if (!(l <= r)) + return AO_LISP_NIL; + break; + case builtin_greater_equal: + if (!(l >= r)) + return AO_LISP_NIL; + break; + default: + break; + } + } else if (lt == AO_LISP_STRING && rt == AO_LISP_STRING) { + int c = strcmp(ao_lisp_poly_string(left), + ao_lisp_poly_string(right)); + switch (op) { + case builtin_less: + if (!(c < 0)) + return AO_LISP_NIL; + break; + case builtin_greater: + if (!(c > 0)) + return AO_LISP_NIL; + break; + case builtin_less_equal: + if (!(c <= 0)) + return AO_LISP_NIL; + break; + case builtin_greater_equal: + if (!(c >= 0)) + return AO_LISP_NIL; + break; + default: + break; + } + } + } + left = right; + cons = ao_lisp_poly_cons(cons->cdr); + } + return _ao_lisp_atom_t; +} + +ao_poly +ao_lisp_equal(struct ao_lisp_cons *cons) +{ + return ao_lisp_compare(cons, builtin_equal); +} + +ao_poly +ao_lisp_less(struct ao_lisp_cons *cons) +{ + return ao_lisp_compare(cons, builtin_less); +} + +ao_poly +ao_lisp_greater(struct ao_lisp_cons *cons) +{ + return ao_lisp_compare(cons, builtin_greater); +} + +ao_poly +ao_lisp_less_equal(struct ao_lisp_cons *cons) +{ + return ao_lisp_compare(cons, builtin_less_equal); +} + +ao_poly +ao_lisp_greater_equal(struct ao_lisp_cons *cons) +{ + return ao_lisp_compare(cons, builtin_greater_equal); } ao_lisp_func_t ao_lisp_builtins[] = { @@ -273,6 +380,11 @@ ao_lisp_func_t ao_lisp_builtins[] = { [builtin_minus] = ao_lisp_minus, [builtin_times] = ao_lisp_times, [builtin_divide] = ao_lisp_divide, - [builtin_mod] = ao_lisp_mod + [builtin_mod] = ao_lisp_mod, + [builtin_equal] = ao_lisp_equal, + [builtin_less] = ao_lisp_less, + [builtin_greater] = ao_lisp_greater, + [builtin_less_equal] = ao_lisp_less_equal, + [builtin_greater_equal] = ao_lisp_greater_equal }; diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c index f8a34ed4..4929b91c 100644 --- a/src/lisp/ao_lisp_cons.c +++ b/src/lisp/ao_lisp_cons.c @@ -16,21 +16,6 @@ #define OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_const)) -#if 0 -static int cons_depth; -#define DBG(...) do { int d; for (d = 0; d < cons_depth; d++) printf (" "); printf(__VA_ARGS__); } while(0) -#define DBG_IN() (cons_depth++) -#define DBG_OUT() (cons_depth--) -#define DBG_PR(c) ao_lisp_cons_print(ao_lisp_cons_poly(c)) -#define DBG_PRP(p) ao_lisp_poly_print(p) -#else -#define DBG(...) -#define DBG_IN() -#define DBG_OUT() -#define DBG_PR(c) -#define DBG_PRP(p) -#endif - static void cons_mark(void *addr) { struct ao_lisp_cons *cons = addr; @@ -55,25 +40,15 @@ static void cons_move(void *addr) { struct ao_lisp_cons *cons = addr; - DBG_IN(); - DBG("move cons start %d\n", OFFSET(cons)); - for (;;) { - struct ao_lisp_cons *cdr; - ao_poly car; + if (!cons) + return; - car = ao_lisp_poly_move(cons->car); - DBG(" moved car %d -> %d\n", OFFSET(ao_lisp_ref(cons->car)), OFFSET(ao_lisp_ref(car))); - cons->car = car; - cdr = ao_lisp_poly_cons(cons->cdr); - cdr = ao_lisp_move_memory(cdr, sizeof (struct ao_lisp_cons)); - if (!cdr) + for (;;) { + (void) ao_lisp_poly_move(&cons->car); + if (ao_lisp_poly_move(&cons->cdr)) break; - DBG(" moved cdr %d -> %d\n", OFFSET(ao_lisp_poly_cons(cons->cdr)), OFFSET(cdr)); - cons->cdr = ao_lisp_cons_poly(cdr); - cons = cdr; + cons = ao_lisp_poly_cons(cons->cdr); } - DBG("move cons end\n"); - DBG_OUT(); } const struct ao_lisp_type ao_lisp_cons_type = { diff --git a/src/lisp/ao_lisp_const.lisp b/src/lisp/ao_lisp_const.lisp index 5ee15899..5ca89bd4 100644 --- a/src/lisp/ao_lisp_const.lisp +++ b/src/lisp/ao_lisp_const.lisp @@ -1,4 +1,7 @@ cadr (lambda (l) (car (cdr l))) +caddr (lambda (l) (car (cdr (cdr l)))) list (lexpr (l) l) 1+ (lambda (x) (+ x 1)) 1- (lambda (x) (- x 1)) +last (lambda (x) (cond ((cdr x) (last (cdr x))) ((car x)))) +prog* (lexpr (l) (last l)) diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index 2b2cfee7..b7e7b972 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -37,8 +37,11 @@ static int stack_depth; enum eval_state { eval_sexpr, eval_val, + eval_formal, eval_exec, - eval_exec_direct + eval_exec_direct, + eval_cond, + eval_cond_test }; struct ao_lisp_stack { @@ -84,20 +87,26 @@ stack_mark(void *addr) } } +static const struct ao_lisp_type ao_lisp_stack_type; + static void stack_move(void *addr) { struct ao_lisp_stack *stack = addr; - for (;;) { - struct ao_lisp_stack *prev; - stack->actuals = ao_lisp_poly_move(stack->actuals); - stack->formals = ao_lisp_poly_move(stack->formals); - stack->frame = ao_lisp_poly_move(stack->frame); - prev = ao_lisp_ref(stack->prev); - prev = ao_lisp_move_memory(prev, sizeof (struct ao_lisp_stack)); - stack->prev = ao_lisp_stack_poly(prev); - stack = prev; + while (stack) { + void *prev; + int ret; + (void) ao_lisp_poly_move(&stack->actuals); + (void) ao_lisp_poly_move(&stack->formals); + (void) ao_lisp_poly_move(&stack->frame); + prev = ao_lisp_poly_stack(stack->prev); + ret = ao_lisp_move(&ao_lisp_stack_type, &prev); + if (prev != ao_lisp_poly_stack(stack->prev)) + stack->prev = ao_lisp_stack_poly(prev); + if (ret); + break; + stack = ao_lisp_poly_stack(stack->prev); } } @@ -107,17 +116,19 @@ static const struct ao_lisp_type ao_lisp_stack_type = { .move = stack_move }; - static struct ao_lisp_stack *ao_lisp_stack; +static ao_poly ao_lisp_v; static uint8_t been_here; ao_poly ao_lisp_set_cond(struct ao_lisp_cons *c) { + ao_lisp_stack->state = eval_cond; + ao_lisp_stack->actuals = ao_lisp_cons_poly(c); return AO_LISP_NIL; } -static void +void ao_lisp_stack_reset(struct ao_lisp_stack *stack) { stack->state = eval_sexpr; @@ -128,21 +139,21 @@ ao_lisp_stack_reset(struct ao_lisp_stack *stack) stack->frame = ao_lisp_frame_poly(ao_lisp_frame_current); } -static struct ao_lisp_stack * +struct ao_lisp_stack * ao_lisp_stack_push(void) { struct ao_lisp_stack *stack = ao_lisp_alloc(sizeof (struct ao_lisp_stack)); if (!stack) return NULL; stack->prev = ao_lisp_stack_poly(ao_lisp_stack); - ao_lisp_stack_reset(stack); ao_lisp_stack = stack; + ao_lisp_stack_reset(stack); DBGI("stack push\n"); DBG_IN(); return stack; } -static struct ao_lisp_stack * +struct ao_lisp_stack * ao_lisp_stack_pop(void) { if (!ao_lisp_stack) @@ -164,7 +175,6 @@ ao_lisp_stack_clear(void) ao_lisp_frame_current = NULL; } - static ao_poly func_type(ao_poly func) { @@ -196,8 +206,11 @@ func_type(ao_poly func) f++; } return ao_lisp_arg(cons, 0); - } else - return ao_lisp_error(AO_LISP_INVALID, "not a func"); + } else { + ao_lisp_error(AO_LISP_INVALID, "not a func"); + abort(); + return AO_LISP_NIL; + } } static int @@ -236,7 +249,7 @@ ao_lisp_lambda(struct ao_lisp_cons *cons) args_provided = 1; if (args_wanted != args_provided) return ao_lisp_error(AO_LISP_INVALID, "need %d args, not %d", args_wanted, args_provided); - next_frame = ao_lisp_frame_new(args_wanted, 0); + next_frame = ao_lisp_frame_new(args_wanted); DBGI("new frame %d\n", OFFSET(next_frame)); switch (type) { case _ao_lisp_atom_lambda: { @@ -268,14 +281,16 @@ ao_lisp_lambda(struct ao_lisp_cons *cons) } ao_poly -ao_lisp_eval(ao_poly v) +ao_lisp_eval(ao_poly _v) { struct ao_lisp_stack *stack; ao_poly formal; + ao_lisp_v = _v; if (!been_here) { been_here = 1; - ao_lisp_root_add(&ao_lisp_stack_type, &stack); + ao_lisp_root_add(&ao_lisp_stack_type, &ao_lisp_stack); + ao_lisp_root_poly_add(&ao_lisp_v); } stack = ao_lisp_stack_push(); @@ -285,19 +300,20 @@ ao_lisp_eval(ao_poly v) return AO_LISP_NIL; switch (stack->state) { case eval_sexpr: - DBGI("sexpr: "); DBG_POLY(v); DBG("\n"); - switch (ao_lisp_poly_type(v)) { + DBGI("sexpr: "); DBG_POLY(ao_lisp_v); DBG("\n"); + switch (ao_lisp_poly_type(ao_lisp_v)) { case AO_LISP_CONS: - if (v == AO_LISP_NIL) { + if (ao_lisp_v == AO_LISP_NIL) { stack->state = eval_exec; break; } - stack->actuals = v; + stack->actuals = ao_lisp_v; + stack->state = eval_formal; stack = ao_lisp_stack_push(); - v = ao_lisp_poly_cons(v)->car; + ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car; break; case AO_LISP_ATOM: - v = ao_lisp_atom_get(v); + ao_lisp_v = ao_lisp_atom_get(ao_lisp_v); /* fall through */ case AO_LISP_INT: case AO_LISP_STRING: @@ -306,15 +322,17 @@ ao_lisp_eval(ao_poly v) } break; case eval_val: - DBGI("val: "); DBG_POLY(v); DBG("\n"); + DBGI("val: "); DBG_POLY(ao_lisp_v); DBG("\n"); stack = ao_lisp_stack_pop(); if (!stack) - return v; + return ao_lisp_v; + DBGI("..state %d\n", stack->state); + break; - stack->state = eval_sexpr; + case eval_formal: /* Check what kind of function we've got */ if (!stack->formals) { - switch (func_type(v)) { + switch (func_type(ao_lisp_v)) { case AO_LISP_LAMBDA: case _ao_lisp_atom_lambda: case AO_LISP_LEXPR: @@ -335,7 +353,7 @@ ao_lisp_eval(ao_poly v) break; } - formal = ao_lisp_cons_poly(ao_lisp_cons_cons(v, NULL)); + formal = ao_lisp_cons_poly(ao_lisp_cons_cons(ao_lisp_v, NULL)); if (!formal) { ao_lisp_stack_clear(); return AO_LISP_NIL; @@ -349,257 +367,78 @@ ao_lisp_eval(ao_poly v) DBGI("formals now "); DBG_POLY(stack->formals); DBG("\n"); - v = ao_lisp_poly_cons(stack->actuals)->cdr; + ao_lisp_v = ao_lisp_poly_cons(stack->actuals)->cdr; + + stack->state = eval_sexpr; break; case eval_exec: - v = ao_lisp_poly_cons(stack->formals)->car; + if (!stack->formals) { + ao_lisp_v = AO_LISP_NIL; + stack->state = eval_val; + break; + } + ao_lisp_v = ao_lisp_poly_cons(stack->formals)->car; case eval_exec_direct: - DBGI("exec: macro %d ", stack->macro); DBG_POLY(v); DBG(" formals "); DBG_POLY(stack->formals); DBG ("\n"); - if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) { - struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v); + DBGI("exec: macro %d ", stack->macro); DBG_POLY(ao_lisp_v); DBG(" formals "); DBG_POLY(stack->formals); DBG ("\n"); + if (ao_lisp_poly_type(ao_lisp_v) == AO_LISP_BUILTIN) { + struct ao_lisp_builtin *b = ao_lisp_poly_builtin(ao_lisp_v); struct ao_lisp_cons *f = ao_lisp_poly_cons(ao_lisp_poly_cons(stack->formals)->cdr); DBGI(".. builtin formals "); DBG_CONS(f); DBG("\n"); - v = ao_lisp_func(b) (f); - DBGI("builtin result:"); DBG_POLY(v); DBG ("\n"); - if (ao_lisp_exception) { - ao_lisp_stack_clear(); - return AO_LISP_NIL; - } if (stack->macro) stack->state = eval_sexpr; else stack->state = eval_val; stack->macro = 0; + ao_lisp_v = ao_lisp_func(b) (f); + DBGI("builtin result:"); DBG_POLY(ao_lisp_v); DBG ("\n"); + if (ao_lisp_exception) { + ao_lisp_stack_clear(); + return AO_LISP_NIL; + } break; } else { - v = ao_lisp_lambda(ao_lisp_poly_cons(stack->formals)); + ao_lisp_v = ao_lisp_lambda(ao_lisp_poly_cons(stack->formals)); ao_lisp_stack_reset(stack); } break; - } - } -} -#if 0 - - - restart: - if (cond) { - DBGI("cond is now "); DBG_CONS(cond); DBG("\n"); - if (cond->car == AO_LISP_NIL) { - cond = AO_LISP_NIL; - v = AO_LISP_NIL; + case eval_cond: + DBGI("cond: "); DBG_POLY(stack->actuals); DBG("\n"); + if (!stack->actuals) { + ao_lisp_v = AO_LISP_NIL; + stack->state = eval_val; } else { - if (ao_lisp_poly_type(cond->car) != AO_LISP_CONS) { - ao_lisp_error(AO_LISP_INVALID, "malformed cond"); + ao_lisp_v = ao_lisp_poly_cons(stack->actuals)->car; + if (!ao_lisp_v || ao_lisp_poly_type(ao_lisp_v) != AO_LISP_CONS) { + ao_lisp_error(AO_LISP_INVALID, "invalid cond clause"); goto bail; } - v = ao_lisp_poly_cons(cond->car)->car; + ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car; + stack->state = eval_cond_test; + stack = ao_lisp_stack_push(); + stack->state = eval_sexpr; } - } - - /* Build stack frames for each list */ - while (ao_lisp_poly_type(v) == AO_LISP_CONS) { - if (v == AO_LISP_NIL) - break; - - /* Push existing bits on the stack */ - if (cons++) - if (!ao_lisp_stack_push()) - goto bail; - - actuals = ao_lisp_poly_cons(v); - formals = NULL; - formals_tail = NULL; - save_cond = cond; - cond = NULL; - - v = actuals->car; - -// DBG("start: stack"); DBG_CONS(stack); DBG("\n"); -// DBG("start: actuals"); DBG_CONS(actuals); DBG("\n"); -// DBG("start: formals"); DBG_CONS(formals); DBG("\n"); - } - - if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) { - struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v); - switch (b->args) { - case AO_LISP_NLAMBDA: - formals = actuals; - goto eval; - - case AO_LISP_MACRO: - v = ao_lisp_func(b)(ao_lisp_poly_cons(actuals->cdr)); - DBG("macro "); DBG_POLY(ao_lisp_cons_poly(actuals)); - DBG(" -> "); DBG_POLY(v); - DBG("\n"); - if (ao_lisp_poly_type(v) != AO_LISP_CONS) { - ao_lisp_error(AO_LISP_INVALID, "macro didn't return list"); - goto bail; - } - /* Reset frame to the new list */ - actuals = ao_lisp_poly_cons(v); - v = actuals->car; - goto restart; - } - /* Evaluate primitive types */ - - DBG ("actual: "); DBG_POLY(v); DBG("\n"); - - switch (ao_lisp_poly_type(v)) { - case AO_LISP_INT: - case AO_LISP_STRING: break; - case AO_LISP_ATOM: - v = ao_lisp_atom_get(v); - break; - } - - while (cons) { - DBG("add formal: "); DBG_POLY(v); DBG("\n"); - - /* We've processed the first element of the list, go check - * what kind of function we've got - */ - if (formals == NULL) { - if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) { - struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v); - switch (b->args) { - case AO_LISP_NLAMBDA: - formals = actuals; - goto eval; - - case AO_LISP_MACRO: - v = ao_lisp_func(b)(ao_lisp_poly_cons(actuals->cdr)); - DBG("macro "); DBG_POLY(ao_lisp_cons_poly(actuals)); - DBG(" -> "); DBG_POLY(v); - DBG("\n"); - if (ao_lisp_poly_type(v) != AO_LISP_CONS) { - ao_lisp_error(AO_LISP_INVALID, "macro didn't return list"); - goto bail; - } - /* Reset frame to the new list */ - actuals = ao_lisp_poly_cons(v); - v = actuals->car; - goto restart; - } + case eval_cond_test: + DBGI("cond_test "); DBG_POLY(ao_lisp_v); DBG("\n"); + if (ao_lisp_v) { + struct ao_lisp_cons *car = ao_lisp_poly_cons(ao_lisp_poly_cons(stack->actuals)->car); + struct ao_lisp_cons *c = ao_lisp_poly_cons(car->cdr); + if (c) { + ao_lisp_v = c->car; + stack->state = eval_sexpr; } else { - switch (func_type(v)) { - case _ao_lisp_atom_lambda: - case _ao_lisp_atom_lexpr: - break; - case _ao_lisp_atom_nlambda: - formals = actuals; - goto eval; - case _ao_lisp_atom_macro: - break; - default: - ao_lisp_error(AO_LISP_INVALID, "operator is not a function"); - goto bail; - } - } - } - - formal = ao_lisp_cons_cons(v, NULL); - if (formals_tail) - formals_tail->cdr = ao_lisp_cons_poly(formal); - else - formals = formal; - formals_tail = formal; - actuals = ao_lisp_poly_cons(actuals->cdr); - - DBG("formals: "); - DBG_CONS(formals); - DBG("\n"); - DBG("actuals: "); - DBG_CONS(actuals); - DBG("\n"); - - /* Process all of the arguments */ - if (actuals) { - v = actuals->car; - break; - } - - v = formals->car; - - eval: - - /* Evaluate the resulting list */ - if (ao_lisp_poly_type(v) == AO_LISP_BUILTIN) { - struct ao_lisp_cons *old_cond = cond; - struct ao_lisp_builtin *b = ao_lisp_poly_builtin(v); - - v = ao_lisp_func(b) (ao_lisp_poly_cons(formals->cdr)); - - DBG ("eval: "); - DBG_CONS(formals); - DBG(" -> "); - DBG_POLY(v); - DBG ("\n"); - if (ao_lisp_exception) - goto bail; - - if (cond != old_cond) { - DBG("cond changed from "); DBG_CONS(old_cond); DBG(" to "); DBG_CONS(cond); DBG("\n"); - actuals = NULL; - formals = 0; - formals_tail = 0; - save_cons = cons; - cons = 0; - goto restart; - } - } else { - v = ao_lisp_lambda(formals); - if (ao_lisp_exception) - goto bail; - } - - cond_done: - --cons; - if (cons) { - ao_lisp_stack_pop(); -// DBG("stack pop: stack"); DBG_CONS(stack); DBG("\n"); -// DBG("stack pop: actuals"); DBG_CONS(actuals); DBG("\n"); -// DBG("stack pop: formals"); DBG_CONS(formals); DBG("\n"); - } else { - actuals = 0; - formals = 0; - formals_tail = 0; - ao_lisp_frame_current = 0; - } - if (next_frame) { - ao_lisp_frame_current = next_frame; - DBG("next frame %d\n", OFFSET(next_frame)); - next_frame = 0; - goto restart; - } - } - if (cond) { - DBG("next cond cons is %d\n", cons); - if (v) { - v = ao_lisp_poly_cons(cond->car)->cdr; - cond = 0; - cons = save_cons; - if (v != AO_LISP_NIL) { - v = ao_lisp_poly_cons(v)->car; - DBG("cond complete, sexpr is "); DBG_POLY(v); DBG("\n"); + stack->state = eval_val; } - goto cond_done; } else { - cond = ao_lisp_poly_cons(cond->cdr); - DBG("next cond is "); DBG_CONS(cond); DBG("\n"); - goto restart; + stack->actuals = ao_lisp_poly_cons(stack->actuals)->cdr; + stack->state = eval_cond; } - } - if (!cons) break; + } } - DBG("leaving frame at %d\n", OFFSET(ao_lisp_frame_current)); - return v; bail: ao_lisp_stack_clear(); return AO_LISP_NIL; -#endif - +} diff --git a/src/lisp/ao_lisp_frame.c b/src/lisp/ao_lisp_frame.c index 1853f6d7..8bf98571 100644 --- a/src/lisp/ao_lisp_frame.c +++ b/src/lisp/ao_lisp_frame.c @@ -33,7 +33,7 @@ frame_size(void *addr) return frame_num_size(frame->num); } -#define OFFSET(a) ((uint8_t *) (ao_lisp_ref(a)) - ao_lisp_const) +#define OFFSET(a) ((int) ((uint8_t *) (ao_lisp_ref(a)) - ao_lisp_const)) static void frame_mark(void *addr) @@ -42,16 +42,19 @@ frame_mark(void *addr) int f; for (;;) { - if (frame->readonly) + DBG("frame mark %p\n", frame); + if (!AO_LISP_IS_POOL(frame)) break; for (f = 0; f < frame->num; f++) { struct ao_lisp_val *v = &frame->vals[f]; - ao_lisp_poly_mark(v->atom); ao_lisp_poly_mark(v->val); - DBG ("\tframe mark atom %s %d val %d at %d\n", ao_lisp_poly_atom(v->atom)->name, OFFSET(v->atom), OFFSET(v->val), f); + DBG ("\tframe mark atom %s %d val %d at %d\n", + ao_lisp_poly_atom(v->atom)->name, + OFFSET(v->atom), OFFSET(v->val), f); } frame = ao_lisp_poly_frame(frame->next); + DBG("frame next %p\n", frame); if (!frame) break; if (ao_lisp_mark_memory(frame, frame_size(frame))) @@ -66,26 +69,19 @@ frame_move(void *addr) int f; for (;;) { - struct ao_lisp_frame *next; - if (frame->readonly) + DBG("frame move %p\n", frame); + if (!AO_LISP_IS_POOL(frame)) break; for (f = 0; f < frame->num; f++) { struct ao_lisp_val *v = &frame->vals[f]; - ao_poly t; - - t = ao_lisp_poly_move(v->atom); - DBG("\t\tatom %s %d -> %d\n", ao_lisp_poly_atom(t)->name, OFFSET(v->atom), OFFSET(t)); - v->atom = t; - t = ao_lisp_poly_move(v->val); - DBG("\t\tval %d -> %d\n", OFFSET(v->val), OFFSET(t)); - v->val = t; + + ao_lisp_poly_move(&v->atom); + DBG("moved atom %s\n", ao_lisp_poly_atom(v->atom)->name); + ao_lisp_poly_move(&v->val); } - next = ao_lisp_poly_frame(frame->next); - if (!next) + if (ao_lisp_poly_move(&frame->next)) break; - next = ao_lisp_move_memory(next, frame_size(next)); - frame->next = ao_lisp_frame_poly(next); - frame = next; + frame = ao_lisp_poly_frame(frame->next); } } @@ -109,7 +105,7 @@ int ao_lisp_frame_set(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val) { while (frame) { - if (!frame->readonly) { + if (!AO_LISP_IS_CONST(frame)) { ao_poly *ref = ao_lisp_frame_ref(frame, atom); if (ref) { *ref = val; @@ -134,28 +130,28 @@ ao_lisp_frame_get(struct ao_lisp_frame *frame, ao_poly atom) } struct ao_lisp_frame * -ao_lisp_frame_new(int num, int readonly) +ao_lisp_frame_new(int num) { struct ao_lisp_frame *frame = ao_lisp_alloc(frame_num_size(num)); if (!frame) return NULL; + frame->type = AO_LISP_FRAME; frame->num = num; - frame->readonly = readonly; frame->next = AO_LISP_NIL; memset(frame->vals, '\0', num * sizeof (struct ao_lisp_val)); return frame; } static struct ao_lisp_frame * -ao_lisp_frame_realloc(struct ao_lisp_frame *frame, int new_num, int readonly) +ao_lisp_frame_realloc(struct ao_lisp_frame *frame, int new_num) { struct ao_lisp_frame *new; int copy; if (new_num == frame->num) return frame; - new = ao_lisp_frame_new(new_num, readonly); + new = ao_lisp_frame_new(new_num); if (!new) return NULL; copy = new_num; @@ -175,10 +171,10 @@ ao_lisp_frame_add(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val) int f; if (frame) { f = frame->num; - frame = ao_lisp_frame_realloc(frame, f + 1, frame->readonly); + frame = ao_lisp_frame_realloc(frame, f + 1); } else { f = 0; - frame = ao_lisp_frame_new(1, 0); + frame = ao_lisp_frame_new(1); } if (!frame) return NULL; diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index 9c2ea74c..9768dc22 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -45,7 +45,12 @@ struct builtin_func funcs[] = { "-", AO_LISP_LEXPR, builtin_minus, "*", AO_LISP_LEXPR, builtin_times, "/", AO_LISP_LEXPR, builtin_divide, - "%", AO_LISP_LEXPR, builtin_mod + "%", AO_LISP_LEXPR, builtin_mod, + "=", AO_LISP_LEXPR, builtin_equal, + "<", AO_LISP_LEXPR, builtin_less, + ">", AO_LISP_LEXPR, builtin_greater, + "<=", AO_LISP_LEXPR, builtin_less_equal, + ">=", AO_LISP_LEXPR, builtin_greater_equal, }; ao_poly @@ -92,7 +97,7 @@ main(int argc, char **argv) printf("/*\n"); printf(" * Generated file, do not edit\n"); ao_lisp_root_add(&ao_lisp_frame_type, &globals); - globals = ao_lisp_frame_new(0, 0); + globals = ao_lisp_frame_new(0); for (f = 0; f < N_FUNC; f++) { b = ao_lisp_make_builtin(funcs[f].func, funcs[f].args); a = ao_lisp_atom_intern(funcs[f].name); @@ -127,8 +132,6 @@ main(int argc, char **argv) ao_lisp_collect(); printf(" */\n"); - globals->readonly = 1; - printf("#define AO_LISP_POOL_CONST %d\n", ao_lisp_top); printf("extern const uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4)));\n"); printf("#define ao_builtin_atoms 0x%04x\n", ao_lisp_atom_poly(ao_lisp_atoms)); diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 27f5b666..29d8dbf4 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -28,9 +28,18 @@ uint8_t ao_lisp_pool[AO_LISP_POOL] __attribute__((aligned(4))); #endif #if 0 +#define DBG_COLLECT_ALWAYS +#endif + +#if 0 +#define DBG_POOL +#endif + +#if 1 #define DBG_DUMP #define DBG_OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_pool)) #define DBG(...) printf(__VA_ARGS__) +#define DBG_DO(a) a static int move_dump; static int move_depth; #define DBG_RESET() (move_depth = 0) @@ -39,6 +48,7 @@ static int move_depth; #define DBG_MOVE_OUT() (move_depth--) #else #define DBG(...) +#define DBG_DO(a) #define DBG_RESET() #define DBG_MOVE(...) #define DBG_MOVE_IN() @@ -162,14 +172,24 @@ move_object(void) DBG_MOVE("move %d -> %d\n", DBG_OFFSET(move_old), DBG_OFFSET(move_new)); DBG_MOVE_IN(); memset(ao_lisp_moving, '\0', sizeof (ao_lisp_moving)); - for (i = 0; i < AO_LISP_ROOT; i++) - if (ao_lisp_root[i].addr && *ao_lisp_root[i].addr) { - void *new; - DBG_MOVE("root %d\n", DBG_OFFSET(*ao_lisp_root[i].addr)); - new = ao_lisp_move(ao_lisp_root[i].type, *ao_lisp_root[i].addr); - if (new) - *ao_lisp_root[i].addr = new; + for (i = 0; i < AO_LISP_ROOT; i++) { + if (!ao_lisp_root[i].addr) + continue; + if (ao_lisp_root[i].type) { + DBG_DO(void *addr = *ao_lisp_root[i].addr); + DBG_MOVE("root %d\n", DBG_OFFSET(addr)); + if (!ao_lisp_move(ao_lisp_root[i].type, + ao_lisp_root[i].addr)) + DBG_MOVE("root moves from %p to %p\n", + addr, + *ao_lisp_root[i].addr); + } else { + DBG_DO(ao_poly p = *(ao_poly *) ao_lisp_root[i].addr); + if (!ao_lisp_poly_move((ao_poly *) ao_lisp_root[i].addr)) + DBG_MOVE("root poly move from %04x to %04x\n", + p, *(ao_poly *) ao_lisp_root[i].addr); } + } DBG_MOVE_OUT(); DBG_MOVE("move done\n"); } @@ -197,20 +217,39 @@ dump_busy(void) #define DUMP_BUSY() #endif +static void +ao_lisp_mark_busy(void) +{ + int i; + + memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy)); + DBG("mark\n"); + for (i = 0; i < AO_LISP_ROOT; i++) { + if (ao_lisp_root[i].type) { + void **a = ao_lisp_root[i].addr, *v; + if (a && (v = *a)) { + DBG("root %p\n", v); + ao_lisp_mark(ao_lisp_root[i].type, v); + } + } else { + ao_poly *a = (ao_poly *) ao_lisp_root[i].addr, p; + if (a && (p = *a)) { + DBG("root %04x\n", p); + ao_lisp_poly_mark(p); + } + } + } +} + void ao_lisp_collect(void) { int i; int top; + DBG("collect\n"); /* Mark */ - memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy)); - DBG("mark\n"); - for (i = 0; i < AO_LISP_ROOT; i++) - if (ao_lisp_root[i].addr && *ao_lisp_root[i].addr) { - DBG("root %p\n", *ao_lisp_root[i].addr); - ao_lisp_mark(ao_lisp_root[i].type, *ao_lisp_root[i].addr); - } + ao_lisp_mark_busy(); DUMP_BUSY(); /* Compact */ @@ -243,14 +282,15 @@ ao_lisp_collect(void) } -void +int ao_lisp_mark(const struct ao_lisp_type *type, void *addr) { if (!addr) - return; + return 1; if (mark_object(ao_lisp_busy, addr, type->size(addr))) - return; + return 1; type->mark(addr); + return 0; } int @@ -290,28 +330,31 @@ check_move(void *addr, int size) return addr; } -void * -ao_lisp_move(const struct ao_lisp_type *type, void *addr) +int +ao_lisp_move(const struct ao_lisp_type *type, void **ref) { - uint8_t *a = addr; - int size = type->size(addr); + void *addr = *ref; + uint8_t *a = addr; + int size = type->size(addr); if (!addr) return NULL; #ifndef AO_LISP_MAKE_CONST if (AO_LISP_IS_CONST(addr)) - return addr; + return 1; #endif DBG_MOVE("object %d\n", DBG_OFFSET(addr)); if (a < ao_lisp_pool || ao_lisp_pool + AO_LISP_POOL <= a) abort(); DBG_MOVE_IN(); addr = check_move(addr, size); + if (addr != *ref) + *ref = addr; if (mark_object(ao_lisp_moving, addr, size)) { DBG_MOVE("already moved\n"); DBG_MOVE_OUT(); - return addr; + return 1; } DBG_MOVE_OUT(); DBG_MOVE("recursing...\n"); @@ -319,35 +362,97 @@ ao_lisp_move(const struct ao_lisp_type *type, void *addr) type->move(addr); DBG_MOVE_OUT(); DBG_MOVE("done %d\n", DBG_OFFSET(addr)); - return addr; + return 0; } -void * -ao_lisp_move_memory(void *addr, int size) +int +ao_lisp_move_memory(void **ref, int size) { + void *addr = *ref; if (!addr) return NULL; DBG_MOVE("memory %d\n", DBG_OFFSET(addr)); DBG_MOVE_IN(); addr = check_move(addr, size); + if (addr != *ref) + *ref = addr; if (mark_object(ao_lisp_moving, addr, size)) { DBG_MOVE("already moved\n"); DBG_MOVE_OUT(); - return addr; + return 1; } DBG_MOVE_OUT(); - return addr; + return 0; +} + +#ifdef DBG_POOL +static int AO_LISP_POOL_CUR = AO_LISP_POOL / 8; + +static void +ao_lisp_poison(void) +{ + int i; + + printf("poison\n"); + ao_lisp_mark_busy(); + for (i = 0; i < AO_LISP_POOL_CUR; i += 4) { + uint32_t *a = (uint32_t *) &ao_lisp_pool[i]; + if (!busy_object(ao_lisp_busy, a)) + *a = 0xBEEFBEEF; + } + for (i = 0; i < AO_LISP_POOL_CUR; i += 2) { + ao_poly *a = (uint16_t *) &ao_lisp_pool[i]; + ao_poly p = *a; + + if (!ao_lisp_is_const(p)) { + void *r = ao_lisp_ref(p); + + if (ao_lisp_pool <= (uint8_t *) r && + (uint8_t *) r <= ao_lisp_pool + AO_LISP_POOL_CUR) + { + if (!busy_object(ao_lisp_busy, r)) { + printf("missing reference from %d to %d\n", + (int) ((uint8_t *) a - ao_lisp_pool), + (int) ((uint8_t *) r - ao_lisp_pool)); + } + } + } + } } +#else +#define AO_LISP_POOL_CUR AO_LISP_POOL +#endif + void * ao_lisp_alloc(int size) { void *addr; size = ao_lisp_mem_round(size); - if (ao_lisp_top + size > AO_LISP_POOL) { +#ifdef DBG_COLLECT_ALWAYS + ao_lisp_collect(); +#endif + if (ao_lisp_top + size > AO_LISP_POOL_CUR) { +#ifdef DBG_POOL + if (AO_LISP_POOL_CUR < AO_LISP_POOL) { + AO_LISP_POOL_CUR += AO_LISP_POOL / 8; + ao_lisp_poison(); + } else +#endif ao_lisp_collect(); +#ifdef DBG_POOL + { + int i; + + for (i = ao_lisp_top; i < AO_LISP_POOL; i += 4) { + uint32_t *p = (uint32_t *) &ao_lisp_pool[i]; + *p = 0xbeefbeef; + } + } +#endif + if (ao_lisp_top + size > AO_LISP_POOL) { ao_lisp_exception |= AO_LISP_OOM; return NULL; @@ -374,6 +479,12 @@ ao_lisp_root_add(const struct ao_lisp_type *type, void *addr) return 0; } +int +ao_lisp_root_poly_add(ao_poly *p) +{ + return ao_lisp_root_add(NULL, p); +} + void ao_lisp_root_clear(void *addr) { diff --git a/src/lisp/ao_lisp_prim.c b/src/lisp/ao_lisp_prim.c index e9367553..7f02505d 100644 --- a/src/lisp/ao_lisp_prim.c +++ b/src/lisp/ao_lisp_prim.c @@ -14,6 +14,12 @@ #include "ao_lisp.h" +#if 0 +#define DBG(...) printf (__VA_ARGS__) +#else +#define DBG(...) +#endif + static void (*const ao_lisp_print_funcs[AO_LISP_NUM_TYPE])(ao_poly) = { [AO_LISP_CONS] = ao_lisp_cons_print, [AO_LISP_STRING] = ao_lisp_string_print, @@ -33,30 +39,52 @@ ao_lisp_poly_print(ao_poly p) static const struct ao_lisp_type const *ao_lisp_types[AO_LISP_NUM_TYPE] = { [AO_LISP_CONS] = &ao_lisp_cons_type, + [AO_LISP_INT] = NULL, [AO_LISP_STRING] = &ao_lisp_string_type, + [AO_LISP_OTHER] = (void *) 0x1, [AO_LISP_ATOM] = &ao_lisp_atom_type, [AO_LISP_BUILTIN] = &ao_lisp_builtin_type, + [AO_LISP_FRAME] = &ao_lisp_frame_type, }; -void +int ao_lisp_poly_mark(ao_poly p) { const struct ao_lisp_type *lisp_type = ao_lisp_types[ao_lisp_poly_type(p)]; if (lisp_type) - ao_lisp_mark(lisp_type, ao_lisp_ref(p)); + return ao_lisp_mark(lisp_type, ao_lisp_ref(p)); + return 1; } -ao_poly -ao_lisp_poly_move(ao_poly p) +int +ao_lisp_poly_move(ao_poly *ref) { - uint8_t type = p & AO_LISP_TYPE_MASK; + uint8_t type; + ao_poly p = *ref; const struct ao_lisp_type *lisp_type; + int ret; + void *addr; + + if (!p) + return 1; + type = p & AO_LISP_TYPE_MASK; if (type == AO_LISP_OTHER) type = ao_lisp_other_type(ao_lisp_move_map(ao_lisp_poly_other(p))); + if (type >= AO_LISP_NUM_TYPE) + abort(); + lisp_type = ao_lisp_types[type]; - if (lisp_type) - p = ao_lisp_poly(ao_lisp_move(lisp_type, ao_lisp_ref(p)), p & AO_LISP_TYPE_MASK); - return p; + if (!lisp_type) + return 1; + addr = ao_lisp_ref(p); + ret = ao_lisp_move(lisp_type, &addr); + if (addr != ao_lisp_ref(p)) { + ao_poly np = ao_lisp_poly(addr, p & AO_LISP_TYPE_MASK); + DBG("poly %d moved %04x -> %04x\n", + type, p, np); + *ref = np; + } + return ret; } -- cgit v1.2.3 From 286d07d83bd7ff361e5a904c151a75e5a9c8b071 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 5 Nov 2016 15:12:05 -0700 Subject: altos/lisp: make sure stack->formals_last gets moved during GC Failing this leads to broken formals chains Signed-off-by: Keith Packard --- src/lisp/ao_lisp_eval.c | 6 ++++-- src/lisp/ao_lisp_mem.c | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index b7e7b972..0de3f190 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -14,7 +14,7 @@ #include "ao_lisp.h" -#if 1 +#if 0 static int stack_depth; #define DBG_INDENT() do { int _s; for(_s = 0; _s < stack_depth; _s++) printf(" "); } while(0) #define DBG_IN() (++stack_depth) @@ -80,6 +80,7 @@ stack_mark(void *addr) for (;;) { ao_lisp_poly_mark(stack->actuals); ao_lisp_poly_mark(stack->formals); + /* no need to mark formals_tail */ ao_lisp_poly_mark(stack->frame); stack = ao_lisp_poly_stack(stack->prev); if (ao_lisp_mark_memory(stack, sizeof (struct ao_lisp_stack))) @@ -99,6 +100,7 @@ stack_move(void *addr) int ret; (void) ao_lisp_poly_move(&stack->actuals); (void) ao_lisp_poly_move(&stack->formals); + (void) ao_lisp_poly_move(&stack->formals_tail); (void) ao_lisp_poly_move(&stack->frame); prev = ao_lisp_poly_stack(stack->prev); ret = ao_lisp_move(&ao_lisp_stack_type, &prev); @@ -250,7 +252,7 @@ ao_lisp_lambda(struct ao_lisp_cons *cons) if (args_wanted != args_provided) return ao_lisp_error(AO_LISP_INVALID, "need %d args, not %d", args_wanted, args_provided); next_frame = ao_lisp_frame_new(args_wanted); - DBGI("new frame %d\n", OFFSET(next_frame)); +// DBGI("new frame %d\n", OFFSET(next_frame)); switch (type) { case _ao_lisp_atom_lambda: { int f; diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 29d8dbf4..9e716da9 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -35,8 +35,8 @@ uint8_t ao_lisp_pool[AO_LISP_POOL] __attribute__((aligned(4))); #define DBG_POOL #endif -#if 1 -#define DBG_DUMP +#if 0 +#define DBG_DUMP 0 #define DBG_OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_pool)) #define DBG(...) printf(__VA_ARGS__) #define DBG_DO(a) a @@ -194,7 +194,7 @@ move_object(void) DBG_MOVE("move done\n"); } -#ifdef DBG_DUMP +#if DBG_DUMP static void dump_busy(void) { -- cgit v1.2.3 From d8cf97fe22acefab40d7bb321138e46d4483fef7 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 5 Nov 2016 17:53:15 -0700 Subject: altos/lisp: more GC issues. add patom Use global ao_lisp_stack instead of local stack so that gc moves of that item work. Signed-off-by: Keith Packard --- src/lambdakey-v1.0/ao_lambdakey.c | 28 ------ src/lambdakey-v1.0/ao_pins.h | 3 +- src/lisp/ao_lisp.h | 12 ++- src/lisp/ao_lisp_builtin.c | 13 +++ src/lisp/ao_lisp_cons.c | 11 +++ src/lisp/ao_lisp_eval.c | 197 +++++++++++++++++++++++++------------- src/lisp/ao_lisp_make_const.c | 1 + src/lisp/ao_lisp_mem.c | 11 ++- src/lisp/ao_lisp_prim.c | 61 +++++++++--- src/lisp/ao_lisp_string.c | 10 ++ src/nucleao-32/ao_pins.h | 3 +- 11 files changed, 237 insertions(+), 113 deletions(-) (limited to 'src') diff --git a/src/lambdakey-v1.0/ao_lambdakey.c b/src/lambdakey-v1.0/ao_lambdakey.c index 6ac78717..8353d811 100644 --- a/src/lambdakey-v1.0/ao_lambdakey.c +++ b/src/lambdakey-v1.0/ao_lambdakey.c @@ -15,39 +15,11 @@ #include #include -static uint16_t blink_delay, blink_running; - -static void blink(void) { - blink_running = 1; - while (blink_delay) { - ao_led_on(AO_LED_RED); - ao_delay(blink_delay); - ao_led_off(AO_LED_RED); - ao_delay(blink_delay); - } - blink_running = 0; - ao_wakeup(&blink_running); - ao_exit(); -} - -struct ao_task blink_task; - -static void blink_cmd() { - ao_cmd_decimal(); - blink_delay = ao_cmd_lex_i; - if (blink_delay && !blink_running) - ao_add_task(&blink_task, blink, "blink"); - if (!blink_delay) - while (blink_running) - ao_sleep(&blink_running); -} - static void lisp_cmd() { ao_lisp_read_eval_print(); } static const struct ao_cmds blink_cmds[] = { - { blink_cmd, "b \0Blink the green LED" }, { lisp_cmd, "l\0Run lisp interpreter" }, { 0, 0 } }; diff --git a/src/lambdakey-v1.0/ao_pins.h b/src/lambdakey-v1.0/ao_pins.h index e379ed12..4da638b9 100644 --- a/src/lambdakey-v1.0/ao_pins.h +++ b/src/lambdakey-v1.0/ao_pins.h @@ -25,7 +25,8 @@ #define AO_LED_RED (1 << LED_PIN_RED) #define AO_LED_PANIC AO_LED_RED #define AO_CMD_LEN 128 -#define AO_LISP_POOL 2048 +#define AO_LISP_POOL 1536 +#define AO_STACK_SIZE 2048 #define LEDS_AVAILABLE (AO_LED_RED) diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 27174e13..0d179942 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -173,6 +173,7 @@ enum ao_lisp_builtin_id { builtin_setq, builtin_cond, builtin_print, + builtin_patom, builtin_plus, builtin_minus, builtin_times, @@ -331,6 +332,9 @@ ao_lisp_cons_cons(ao_poly car, struct ao_lisp_cons *cdr); void ao_lisp_cons_print(ao_poly); +void +ao_lisp_cons_patom(ao_poly); + /* string */ extern const struct ao_lisp_type ao_lisp_string_type; @@ -346,6 +350,9 @@ ao_lisp_string_cat(char *a, char *b); void ao_lisp_string_print(ao_poly s); +void +ao_lisp_string_patom(ao_poly s); + /* atom */ extern const struct ao_lisp_type ao_lisp_atom_type; @@ -370,9 +377,12 @@ void ao_lisp_int_print(ao_poly i); /* prim */ -ao_poly +void ao_lisp_poly_print(ao_poly p); +void +ao_lisp_poly_patom(ao_poly p); + int ao_lisp_poly_mark(ao_poly p); diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index 0ad1f464..49b6c37d 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -179,6 +179,18 @@ ao_lisp_print(struct ao_lisp_cons *cons) return val; } +ao_poly +ao_lisp_patom(struct ao_lisp_cons *cons) +{ + ao_poly val = AO_LISP_NIL; + while (cons) { + val = cons->car; + ao_lisp_poly_patom(val); + cons = ao_lisp_poly_cons(cons->cdr); + } + return val; +} + ao_poly ao_lisp_math(struct ao_lisp_cons *cons, enum ao_lisp_builtin_id op) { @@ -376,6 +388,7 @@ ao_lisp_func_t ao_lisp_builtins[] = { [builtin_setq] = ao_lisp_setq, [builtin_cond] = ao_lisp_cond, [builtin_print] = ao_lisp_print, + [builtin_patom] = ao_lisp_patom, [builtin_plus] = ao_lisp_plus, [builtin_minus] = ao_lisp_minus, [builtin_times] = ao_lisp_times, diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c index 4929b91c..7d3ca68d 100644 --- a/src/lisp/ao_lisp_cons.c +++ b/src/lisp/ao_lisp_cons.c @@ -83,3 +83,14 @@ ao_lisp_cons_print(ao_poly c) } printf(")"); } + +void +ao_lisp_cons_patom(ao_poly c) +{ + struct ao_lisp_cons *cons = ao_lisp_poly_cons(c); + + while (cons) { + ao_lisp_poly_patom(cons->car); + cons = ao_lisp_poly_cons(cons->cdr); + } +} diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index 0de3f190..e3d653b9 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -15,12 +15,13 @@ #include "ao_lisp.h" #if 0 +#define DBG_CODE 1 static int stack_depth; #define DBG_INDENT() do { int _s; for(_s = 0; _s < stack_depth; _s++) printf(" "); } while(0) #define DBG_IN() (++stack_depth) #define DBG_OUT() (--stack_depth) #define DBG(...) printf(__VA_ARGS__) -#define DBGI(...) do { DBG_INDENT(); DBG(__VA_ARGS__); } while (0) +#define DBGI(...) do { DBG_INDENT(); DBG("%4d: ", __LINE__); DBG(__VA_ARGS__); } while (0) #define DBG_CONS(a) ao_lisp_cons_print(ao_lisp_cons_poly(a)) #define DBG_POLY(a) ao_lisp_poly_print(a) #define OFFSET(a) ((a) ? (int) ((uint8_t *) a - ao_lisp_pool) : -1) @@ -90,6 +91,29 @@ stack_mark(void *addr) static const struct ao_lisp_type ao_lisp_stack_type; +#if DBG_CODE +static void +stack_validate_tail(struct ao_lisp_stack *stack) +{ + struct ao_lisp_cons *head = ao_lisp_poly_cons(stack->formals); + struct ao_lisp_cons *tail = ao_lisp_poly_cons(stack->formals_tail); + struct ao_lisp_cons *cons; + for (cons = head; cons && cons->cdr && cons != tail; cons = ao_lisp_poly_cons(cons->cdr)) + ; + if (cons != tail || (tail && tail->cdr)) { + if (!tail) { + printf("tail null\n"); + } else { + printf("tail validate fail head %d actual %d recorded %d\n", + OFFSET(head), OFFSET(cons), OFFSET(tail)); + abort(); + } + } +} +#else +#define stack_validate_tail(s) +#endif + static void stack_move(void *addr) { @@ -106,7 +130,8 @@ stack_move(void *addr) ret = ao_lisp_move(&ao_lisp_stack_type, &prev); if (prev != ao_lisp_poly_stack(stack->prev)) stack->prev = ao_lisp_stack_poly(prev); - if (ret); + stack_validate_tail(stack); + if (ret) break; stack = ao_lisp_poly_stack(stack->prev); } @@ -122,6 +147,19 @@ static struct ao_lisp_stack *ao_lisp_stack; static ao_poly ao_lisp_v; static uint8_t been_here; +#if DBG_CODE +static void +stack_validate_tails(void) +{ + struct ao_lisp_stack *stack; + + for (stack = ao_lisp_stack; stack; stack = ao_lisp_poly_stack(stack->prev)) + stack_validate_tail(stack); +} +#else +#define stack_validate_tails(s) +#endif + ao_poly ao_lisp_set_cond(struct ao_lisp_cons *c) { @@ -139,27 +177,35 @@ ao_lisp_stack_reset(struct ao_lisp_stack *stack) stack->formals = AO_LISP_NIL; stack->formals_tail = AO_LISP_NIL; stack->frame = ao_lisp_frame_poly(ao_lisp_frame_current); + stack_validate_tails(); } -struct ao_lisp_stack * +int ao_lisp_stack_push(void) { + stack_validate_tails(); + if (ao_lisp_stack) { + DBGI("formals "); DBG_POLY(ao_lisp_stack->formals); DBG("\n"); + DBGI("actuals "); DBG_POLY(ao_lisp_stack->actuals); DBG("\n"); + } + DBGI("stack push\n"); + DBG_IN(); struct ao_lisp_stack *stack = ao_lisp_alloc(sizeof (struct ao_lisp_stack)); if (!stack) - return NULL; + return 0; stack->prev = ao_lisp_stack_poly(ao_lisp_stack); ao_lisp_stack = stack; ao_lisp_stack_reset(stack); - DBGI("stack push\n"); - DBG_IN(); - return stack; + stack_validate_tails(); + return 1; } -struct ao_lisp_stack * +void ao_lisp_stack_pop(void) { if (!ao_lisp_stack) - return NULL; + return; + stack_validate_tails(); DBG_OUT(); DBGI("stack pop\n"); ao_lisp_stack = ao_lisp_poly_stack(ao_lisp_stack->prev); @@ -167,12 +213,16 @@ ao_lisp_stack_pop(void) ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->frame); else ao_lisp_frame_current = NULL; - return ao_lisp_stack; + if (ao_lisp_stack) { + DBGI("formals "); DBG_POLY(ao_lisp_stack->formals); DBG("\n"); + DBGI("actuals "); DBG_POLY(ao_lisp_stack->actuals); DBG("\n"); + } } static void ao_lisp_stack_clear(void) { + stack_validate_tails(); ao_lisp_stack = NULL; ao_lisp_frame_current = NULL; } @@ -285,7 +335,6 @@ ao_lisp_lambda(struct ao_lisp_cons *cons) ao_poly ao_lisp_eval(ao_poly _v) { - struct ao_lisp_stack *stack; ao_poly formal; ao_lisp_v = _v; @@ -295,45 +344,50 @@ ao_lisp_eval(ao_poly _v) ao_lisp_root_poly_add(&ao_lisp_v); } - stack = ao_lisp_stack_push(); + if (!ao_lisp_stack_push()) + goto bail; for (;;) { if (ao_lisp_exception) - return AO_LISP_NIL; - switch (stack->state) { + goto bail; + switch (ao_lisp_stack->state) { case eval_sexpr: DBGI("sexpr: "); DBG_POLY(ao_lisp_v); DBG("\n"); switch (ao_lisp_poly_type(ao_lisp_v)) { case AO_LISP_CONS: if (ao_lisp_v == AO_LISP_NIL) { - stack->state = eval_exec; + ao_lisp_stack->state = eval_exec; break; } - stack->actuals = ao_lisp_v; - stack->state = eval_formal; - stack = ao_lisp_stack_push(); + ao_lisp_stack->actuals = ao_lisp_v; + DBGI("actuals now "); DBG_POLY(ao_lisp_v); DBG("\n"); + ao_lisp_stack->state = eval_formal; + if (!ao_lisp_stack_push()) + goto bail; ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car; + stack_validate_tails(); break; case AO_LISP_ATOM: ao_lisp_v = ao_lisp_atom_get(ao_lisp_v); /* fall through */ case AO_LISP_INT: case AO_LISP_STRING: - stack->state = eval_val; + case AO_LISP_BUILTIN: + ao_lisp_stack->state = eval_val; break; } break; case eval_val: DBGI("val: "); DBG_POLY(ao_lisp_v); DBG("\n"); - stack = ao_lisp_stack_pop(); - if (!stack) + ao_lisp_stack_pop(); + if (!ao_lisp_stack) return ao_lisp_v; - DBGI("..state %d\n", stack->state); + DBGI("..state %d\n", ao_lisp_stack->state); break; case eval_formal: /* Check what kind of function we've got */ - if (!stack->formals) { + if (!ao_lisp_stack->formals) { switch (func_type(ao_lisp_v)) { case AO_LISP_LAMBDA: case _ao_lisp_atom_lambda: @@ -343,99 +397,108 @@ ao_lisp_eval(ao_poly _v) break; case AO_LISP_MACRO: case _ao_lisp_atom_macro: - stack->macro = 1; + ao_lisp_stack->macro = 1; case AO_LISP_NLAMBDA: case _ao_lisp_atom_nlambda: DBGI(".. nlambda or macro\n"); - stack->formals = stack->actuals; - stack->state = eval_exec_direct; + ao_lisp_stack->formals = ao_lisp_stack->actuals; + ao_lisp_stack->formals_tail = AO_LISP_NIL; + ao_lisp_stack->state = eval_exec_direct; + stack_validate_tails(); break; } - if (stack->state == eval_exec_direct) + if (ao_lisp_stack->state == eval_exec_direct) break; } + DBGI("add formal "); DBG_POLY(ao_lisp_v); DBG("\n"); + stack_validate_tails(); formal = ao_lisp_cons_poly(ao_lisp_cons_cons(ao_lisp_v, NULL)); - if (!formal) { - ao_lisp_stack_clear(); - return AO_LISP_NIL; - } + stack_validate_tails(); + if (!formal) + goto bail; - if (stack->formals_tail) - ao_lisp_poly_cons(stack->formals_tail)->cdr = formal; + if (ao_lisp_stack->formals_tail) + ao_lisp_poly_cons(ao_lisp_stack->formals_tail)->cdr = formal; else - stack->formals = formal; - stack->formals_tail = formal; + ao_lisp_stack->formals = formal; + ao_lisp_stack->formals_tail = formal; - DBGI("formals now "); DBG_POLY(stack->formals); DBG("\n"); + DBGI("formals now "); DBG_POLY(ao_lisp_stack->formals); DBG("\n"); - ao_lisp_v = ao_lisp_poly_cons(stack->actuals)->cdr; + ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->actuals)->cdr; - stack->state = eval_sexpr; + stack_validate_tails(); + ao_lisp_stack->state = eval_sexpr; break; case eval_exec: - if (!stack->formals) { + if (!ao_lisp_stack->formals) { ao_lisp_v = AO_LISP_NIL; - stack->state = eval_val; + ao_lisp_stack->state = eval_val; break; } - ao_lisp_v = ao_lisp_poly_cons(stack->formals)->car; + ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->formals)->car; case eval_exec_direct: - DBGI("exec: macro %d ", stack->macro); DBG_POLY(ao_lisp_v); DBG(" formals "); DBG_POLY(stack->formals); DBG ("\n"); + DBGI("exec: macro %d ", ao_lisp_stack->macro); DBG_POLY(ao_lisp_v); DBG(" formals "); DBG_POLY(ao_lisp_stack->formals); DBG ("\n"); if (ao_lisp_poly_type(ao_lisp_v) == AO_LISP_BUILTIN) { - struct ao_lisp_builtin *b = ao_lisp_poly_builtin(ao_lisp_v); - struct ao_lisp_cons *f = ao_lisp_poly_cons(ao_lisp_poly_cons(stack->formals)->cdr); + stack_validate_tails(); + struct ao_lisp_builtin *b = ao_lisp_poly_builtin(ao_lisp_v); + stack_validate_tails(); + struct ao_lisp_cons *f = ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->formals)->cdr); DBGI(".. builtin formals "); DBG_CONS(f); DBG("\n"); - if (stack->macro) - stack->state = eval_sexpr; + stack_validate_tails(); + if (ao_lisp_stack->macro) + ao_lisp_stack->state = eval_sexpr; else - stack->state = eval_val; - stack->macro = 0; + ao_lisp_stack->state = eval_val; + ao_lisp_stack->macro = 0; + ao_lisp_stack->actuals = ao_lisp_stack->formals = ao_lisp_stack->formals_tail = AO_LISP_NIL; ao_lisp_v = ao_lisp_func(b) (f); DBGI("builtin result:"); DBG_POLY(ao_lisp_v); DBG ("\n"); - if (ao_lisp_exception) { - ao_lisp_stack_clear(); - return AO_LISP_NIL; - } + if (ao_lisp_exception) + goto bail; break; } else { - ao_lisp_v = ao_lisp_lambda(ao_lisp_poly_cons(stack->formals)); - ao_lisp_stack_reset(stack); + ao_lisp_v = ao_lisp_lambda(ao_lisp_poly_cons(ao_lisp_stack->formals)); + ao_lisp_stack_reset(ao_lisp_stack); } break; case eval_cond: - DBGI("cond: "); DBG_POLY(stack->actuals); DBG("\n"); - if (!stack->actuals) { + DBGI("cond: "); DBG_POLY(ao_lisp_stack->actuals); DBG("\n"); + if (!ao_lisp_stack->actuals) { ao_lisp_v = AO_LISP_NIL; - stack->state = eval_val; + ao_lisp_stack->state = eval_val; } else { - ao_lisp_v = ao_lisp_poly_cons(stack->actuals)->car; + ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->actuals)->car; if (!ao_lisp_v || ao_lisp_poly_type(ao_lisp_v) != AO_LISP_CONS) { ao_lisp_error(AO_LISP_INVALID, "invalid cond clause"); goto bail; } ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car; - stack->state = eval_cond_test; - stack = ao_lisp_stack_push(); - stack->state = eval_sexpr; + ao_lisp_stack->state = eval_cond_test; + stack_validate_tails(); + ao_lisp_stack_push(); + stack_validate_tails(); + ao_lisp_stack->state = eval_sexpr; } break; case eval_cond_test: - DBGI("cond_test "); DBG_POLY(ao_lisp_v); DBG("\n"); + DBGI("cond_test: "); DBG_POLY(ao_lisp_v); DBG(" actuals "); DBG_POLY(ao_lisp_stack->actuals); DBG("\n"); if (ao_lisp_v) { - struct ao_lisp_cons *car = ao_lisp_poly_cons(ao_lisp_poly_cons(stack->actuals)->car); + struct ao_lisp_cons *car = ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->actuals)->car); struct ao_lisp_cons *c = ao_lisp_poly_cons(car->cdr); if (c) { ao_lisp_v = c->car; - stack->state = eval_sexpr; + ao_lisp_stack->state = eval_sexpr; } else { - stack->state = eval_val; + ao_lisp_stack->state = eval_val; } } else { - stack->actuals = ao_lisp_poly_cons(stack->actuals)->cdr; - stack->state = eval_cond; + ao_lisp_stack->actuals = ao_lisp_poly_cons(ao_lisp_stack->actuals)->cdr; + DBGI("actuals now "); DBG_POLY(ao_lisp_stack->actuals); DBG("\n"); + ao_lisp_stack->state = eval_cond; } break; } diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index 9768dc22..f2e3cea1 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -41,6 +41,7 @@ struct builtin_func funcs[] = { "setq", AO_LISP_MACRO, builtin_setq, "cond", AO_LISP_NLAMBDA,builtin_cond, "print", AO_LISP_LEXPR, builtin_print, + "patom", AO_LISP_LEXPR, builtin_patom, "+", AO_LISP_LEXPR, builtin_plus, "-", AO_LISP_LEXPR, builtin_minus, "*", AO_LISP_LEXPR, builtin_times, diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 9e716da9..6e656454 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -36,6 +36,7 @@ uint8_t ao_lisp_pool[AO_LISP_POOL] __attribute__((aligned(4))); #endif #if 0 +#define DBG_INCLUDE #define DBG_DUMP 0 #define DBG_OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_pool)) #define DBG(...) printf(__VA_ARGS__) @@ -179,15 +180,17 @@ move_object(void) DBG_DO(void *addr = *ao_lisp_root[i].addr); DBG_MOVE("root %d\n", DBG_OFFSET(addr)); if (!ao_lisp_move(ao_lisp_root[i].type, - ao_lisp_root[i].addr)) + ao_lisp_root[i].addr)) { DBG_MOVE("root moves from %p to %p\n", addr, *ao_lisp_root[i].addr); + } } else { DBG_DO(ao_poly p = *(ao_poly *) ao_lisp_root[i].addr); - if (!ao_lisp_poly_move((ao_poly *) ao_lisp_root[i].addr)) + if (!ao_lisp_poly_move((ao_poly *) ao_lisp_root[i].addr)) { DBG_MOVE("root poly move from %04x to %04x\n", p, *(ao_poly *) ao_lisp_root[i].addr); + } } } DBG_MOVE_OUT(); @@ -338,7 +341,7 @@ ao_lisp_move(const struct ao_lisp_type *type, void **ref) int size = type->size(addr); if (!addr) - return NULL; + return 1; #ifndef AO_LISP_MAKE_CONST if (AO_LISP_IS_CONST(addr)) @@ -370,7 +373,7 @@ ao_lisp_move_memory(void **ref, int size) { void *addr = *ref; if (!addr) - return NULL; + return 1; DBG_MOVE("memory %d\n", DBG_OFFSET(addr)); DBG_MOVE_IN(); diff --git a/src/lisp/ao_lisp_prim.c b/src/lisp/ao_lisp_prim.c index 7f02505d..82386a83 100644 --- a/src/lisp/ao_lisp_prim.c +++ b/src/lisp/ao_lisp_prim.c @@ -20,21 +20,60 @@ #define DBG(...) #endif -static void (*const ao_lisp_print_funcs[AO_LISP_NUM_TYPE])(ao_poly) = { - [AO_LISP_CONS] = ao_lisp_cons_print, - [AO_LISP_STRING] = ao_lisp_string_print, - [AO_LISP_INT] = ao_lisp_int_print, - [AO_LISP_ATOM] = ao_lisp_atom_print, - [AO_LISP_BUILTIN] = ao_lisp_builtin_print +struct ao_lisp_funcs { + void (*print)(ao_poly); + void (*patom)(ao_poly); }; -ao_poly +static const struct ao_lisp_funcs ao_lisp_funcs[AO_LISP_NUM_TYPE] = { + [AO_LISP_CONS] = { + .print = ao_lisp_cons_print, + .patom = ao_lisp_cons_patom, + }, + [AO_LISP_STRING] = { + .print = ao_lisp_string_print, + .patom = ao_lisp_string_patom, + }, + [AO_LISP_INT] = { + .print = ao_lisp_int_print, + .patom = ao_lisp_int_print, + }, + [AO_LISP_ATOM] = { + .print = ao_lisp_atom_print, + .patom = ao_lisp_atom_print, + }, + [AO_LISP_BUILTIN] = { + .print = ao_lisp_builtin_print, + .patom = ao_lisp_builtin_print, + } +}; + +static const struct ao_lisp_funcs * +funcs(ao_poly p) +{ + uint8_t type = ao_lisp_poly_type(p); + + if (type < AO_LISP_NUM_TYPE) + return &ao_lisp_funcs[type]; + return NULL; +} + +void ao_lisp_poly_print(ao_poly p) { - void (*print)(ao_poly) = ao_lisp_print_funcs[ao_lisp_poly_type(p)]; - if (print) - print(p); - return p; + const struct ao_lisp_funcs *f = funcs(p); + + if (f && f->print) + f->print(p); +} + +void +ao_lisp_poly_patom(ao_poly p) +{ + const struct ao_lisp_funcs *f = funcs(p); + + if (f && f->patom) + f->patom(p); } static const struct ao_lisp_type const *ao_lisp_types[AO_LISP_NUM_TYPE] = { diff --git a/src/lisp/ao_lisp_string.c b/src/lisp/ao_lisp_string.c index 39c3dc81..0064064c 100644 --- a/src/lisp/ao_lisp_string.c +++ b/src/lisp/ao_lisp_string.c @@ -99,3 +99,13 @@ ao_lisp_string_print(ao_poly p) } putchar('"'); } + +void +ao_lisp_string_patom(ao_poly p) +{ + char *s = ao_lisp_poly_string(p); + char c; + + while ((c = *s++)) + putchar(c); +} diff --git a/src/nucleao-32/ao_pins.h b/src/nucleao-32/ao_pins.h index 65de89ed..092d347c 100644 --- a/src/nucleao-32/ao_pins.h +++ b/src/nucleao-32/ao_pins.h @@ -25,7 +25,8 @@ #define AO_LED_GREEN (1 << LED_PIN_GREEN) #define AO_LED_PANIC AO_LED_GREEN #define AO_CMD_LEN 128 -#define AO_LISP_POOL 2048 +#define AO_LISP_POOL 1024 +#define AO_STACK_SIZE 1536 #define LEDS_AVAILABLE (AO_LED_GREEN) -- cgit v1.2.3 From 6e5c1308ce33a864095eae02e7db18b0e043ab6e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 6 Nov 2016 10:53:46 -0800 Subject: altos/lisp: convert GC to non-recursive Use a boolean array to note cons cells which would otherwise recurse, then loop until that array is empty. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 8 ++- src/lisp/ao_lisp_atom.c | 2 +- src/lisp/ao_lisp_cons.c | 15 +++-- src/lisp/ao_lisp_eval.c | 14 ++--- src/lisp/ao_lisp_frame.c | 19 +++++-- src/lisp/ao_lisp_mem.c | 140 ++++++++++++++++++++++++++++++++++++++++++++--- src/lisp/ao_lisp_prim.c | 51 ----------------- 7 files changed, 170 insertions(+), 79 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 0d179942..17f1e0f5 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -221,6 +221,10 @@ ao_lisp_mem_round(int size) #define AO_LISP_OTHER_POLY(other) ((ao_poly)(other) + AO_LISP_OTHER) +static inline int ao_lisp_poly_base_type(ao_poly poly) { + return poly & AO_LISP_TYPE_MASK; +} + static inline int ao_lisp_poly_type(ao_poly poly) { int type = poly & AO_LISP_TYPE_MASK; if (type == AO_LISP_OTHER) @@ -384,11 +388,11 @@ void ao_lisp_poly_patom(ao_poly p); int -ao_lisp_poly_mark(ao_poly p); +ao_lisp_poly_mark(ao_poly p, uint8_t note_cons); /* returns 1 if the object has already been moved */ int -ao_lisp_poly_move(ao_poly *p); +ao_lisp_poly_move(ao_poly *p, uint8_t note_cons); /* eval */ diff --git a/src/lisp/ao_lisp_atom.c b/src/lisp/ao_lisp_atom.c index 5f1bcda0..41ba97f5 100644 --- a/src/lisp/ao_lisp_atom.c +++ b/src/lisp/ao_lisp_atom.c @@ -48,7 +48,7 @@ static void atom_move(void *addr) struct ao_lisp_atom *atom = addr; for (;;) { - if (ao_lisp_poly_move(&atom->next)) + if (ao_lisp_poly_move(&atom->next, 0)) break; atom = ao_lisp_poly_atom(atom->next); } diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c index 7d3ca68d..855079b8 100644 --- a/src/lisp/ao_lisp_cons.c +++ b/src/lisp/ao_lisp_cons.c @@ -21,7 +21,7 @@ static void cons_mark(void *addr) struct ao_lisp_cons *cons = addr; for (;;) { - ao_lisp_poly_mark(cons->car); + ao_lisp_poly_mark(cons->car, 1); cons = ao_lisp_poly_cons(cons->cdr); if (!cons) break; @@ -44,10 +44,17 @@ static void cons_move(void *addr) return; for (;;) { - (void) ao_lisp_poly_move(&cons->car); - if (ao_lisp_poly_move(&cons->cdr)) + struct ao_lisp_cons *cdr; + int ret; + + (void) ao_lisp_poly_move(&cons->car, 1); + cdr = ao_lisp_poly_cons(cons->cdr); + ret = ao_lisp_move_memory((void **) &cdr, sizeof (struct ao_lisp_cons)); + if (cdr != ao_lisp_poly_cons(cons->cdr)) + cons->cdr = ao_lisp_cons_poly(cdr); + if (ret) break; - cons = ao_lisp_poly_cons(cons->cdr); + cons = cdr; } } diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index e3d653b9..a5c74250 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -79,10 +79,10 @@ stack_mark(void *addr) { struct ao_lisp_stack *stack = addr; for (;;) { - ao_lisp_poly_mark(stack->actuals); - ao_lisp_poly_mark(stack->formals); + ao_lisp_poly_mark(stack->actuals, 0); + ao_lisp_poly_mark(stack->formals, 0); /* no need to mark formals_tail */ - ao_lisp_poly_mark(stack->frame); + ao_lisp_poly_mark(stack->frame, 0); stack = ao_lisp_poly_stack(stack->prev); if (ao_lisp_mark_memory(stack, sizeof (struct ao_lisp_stack))) break; @@ -122,10 +122,10 @@ stack_move(void *addr) while (stack) { void *prev; int ret; - (void) ao_lisp_poly_move(&stack->actuals); - (void) ao_lisp_poly_move(&stack->formals); - (void) ao_lisp_poly_move(&stack->formals_tail); - (void) ao_lisp_poly_move(&stack->frame); + (void) ao_lisp_poly_move(&stack->actuals, 0); + (void) ao_lisp_poly_move(&stack->formals, 0); + (void) ao_lisp_poly_move(&stack->formals_tail, 0); + (void) ao_lisp_poly_move(&stack->frame, 0); prev = ao_lisp_poly_stack(stack->prev); ret = ao_lisp_move(&ao_lisp_stack_type, &prev); if (prev != ao_lisp_poly_stack(stack->prev)) diff --git a/src/lisp/ao_lisp_frame.c b/src/lisp/ao_lisp_frame.c index 8bf98571..8791c4de 100644 --- a/src/lisp/ao_lisp_frame.c +++ b/src/lisp/ao_lisp_frame.c @@ -48,7 +48,7 @@ frame_mark(void *addr) for (f = 0; f < frame->num; f++) { struct ao_lisp_val *v = &frame->vals[f]; - ao_lisp_poly_mark(v->val); + ao_lisp_poly_mark(v->val, 0); DBG ("\tframe mark atom %s %d val %d at %d\n", ao_lisp_poly_atom(v->atom)->name, OFFSET(v->atom), OFFSET(v->val), f); @@ -69,19 +69,28 @@ frame_move(void *addr) int f; for (;;) { + struct ao_lisp_frame *next; + int ret; + DBG("frame move %p\n", frame); if (!AO_LISP_IS_POOL(frame)) break; for (f = 0; f < frame->num; f++) { struct ao_lisp_val *v = &frame->vals[f]; - ao_lisp_poly_move(&v->atom); + ao_lisp_poly_move(&v->atom, 0); DBG("moved atom %s\n", ao_lisp_poly_atom(v->atom)->name); - ao_lisp_poly_move(&v->val); + ao_lisp_poly_move(&v->val, 0); } - if (ao_lisp_poly_move(&frame->next)) + next = ao_lisp_poly_frame(frame->next); + ret = 1; + if (next) + ret = ao_lisp_move_memory((void **) &next, frame_size(next)); + if (next != ao_lisp_poly_frame(frame->next)) + frame->next = ao_lisp_frame_poly(next); + if (ret) break; - frame = ao_lisp_poly_frame(frame->next); + frame = next; } } diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 6e656454..c11ec25d 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -41,7 +41,7 @@ uint8_t ao_lisp_pool[AO_LISP_POOL] __attribute__((aligned(4))); #define DBG_OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_pool)) #define DBG(...) printf(__VA_ARGS__) #define DBG_DO(a) a -static int move_dump; +static int move_dump = 1; static int move_depth; #define DBG_RESET() (move_depth = 0) #define DBG_MOVE(...) do { if(move_dump) { int d; for (d = 0; d < move_depth; d++) printf (" "); printf(__VA_ARGS__); } } while (0) @@ -68,8 +68,10 @@ struct ao_lisp_root { static struct ao_lisp_root ao_lisp_root[AO_LISP_ROOT]; static uint8_t ao_lisp_busy[AO_LISP_POOL / 32]; - static uint8_t ao_lisp_moving[AO_LISP_POOL / 32]; +static uint8_t ao_lisp_cons[AO_LISP_POOL / 32]; +static uint8_t ao_lisp_cons_last[AO_LISP_POOL / 32]; +static uint8_t ao_lisp_cons_noted; uint16_t ao_lisp_top; @@ -161,6 +163,17 @@ busy_object(uint8_t *tag, void *addr) { return 0; } +static void +note_cons(void *addr) +{ + DBG_MOVE("note cons %d\n", DBG_OFFSET(addr)); + if (AO_LISP_IS_POOL(addr)) { + ao_lisp_cons_noted = 1; + mark(ao_lisp_cons, (uint8_t *) addr - ao_lisp_pool); + } +} + + static void *move_old, *move_new; static int move_size; @@ -173,11 +186,15 @@ move_object(void) DBG_MOVE("move %d -> %d\n", DBG_OFFSET(move_old), DBG_OFFSET(move_new)); DBG_MOVE_IN(); memset(ao_lisp_moving, '\0', sizeof (ao_lisp_moving)); + memset(ao_lisp_cons, '\0', sizeof (ao_lisp_cons)); + ao_lisp_cons_noted = 0; for (i = 0; i < AO_LISP_ROOT; i++) { if (!ao_lisp_root[i].addr) continue; if (ao_lisp_root[i].type) { - DBG_DO(void *addr = *ao_lisp_root[i].addr); + void *addr = *ao_lisp_root[i].addr; + if (!addr) + continue; DBG_MOVE("root %d\n", DBG_OFFSET(addr)); if (!ao_lisp_move(ao_lisp_root[i].type, ao_lisp_root[i].addr)) { @@ -186,13 +203,30 @@ move_object(void) *ao_lisp_root[i].addr); } } else { - DBG_DO(ao_poly p = *(ao_poly *) ao_lisp_root[i].addr); - if (!ao_lisp_poly_move((ao_poly *) ao_lisp_root[i].addr)) { + ao_poly p = *(ao_poly *) ao_lisp_root[i].addr; + if (!p) + continue; + if (!ao_lisp_poly_move((ao_poly *) ao_lisp_root[i].addr, 0)) { DBG_MOVE("root poly move from %04x to %04x\n", p, *(ao_poly *) ao_lisp_root[i].addr); } } } + while (ao_lisp_cons_noted) { + memcpy(ao_lisp_cons_last, ao_lisp_cons, sizeof (ao_lisp_cons)); + memset(ao_lisp_cons, '\0', sizeof (ao_lisp_cons)); + ao_lisp_cons_noted = 0; + for (i = 0; i < AO_LISP_POOL; i += 4) { + if (busy(ao_lisp_cons_last, i)) { + void *addr = ao_lisp_pool + i; + DBG_MOVE("cons %d\n", DBG_OFFSET(addr)); + if (!ao_lisp_move(&ao_lisp_cons_type, &addr)) { + DBG_MOVE("cons moves from %p to %p\n", + ao_lisp_pool + i, addr); + } + } + } + } DBG_MOVE_OUT(); DBG_MOVE("move done\n"); } @@ -220,25 +254,50 @@ dump_busy(void) #define DUMP_BUSY() #endif +static const struct ao_lisp_type const *ao_lisp_types[AO_LISP_NUM_TYPE] = { + [AO_LISP_CONS] = &ao_lisp_cons_type, + [AO_LISP_INT] = NULL, + [AO_LISP_STRING] = &ao_lisp_string_type, + [AO_LISP_OTHER] = (void *) 0x1, + [AO_LISP_ATOM] = &ao_lisp_atom_type, + [AO_LISP_BUILTIN] = &ao_lisp_builtin_type, + [AO_LISP_FRAME] = &ao_lisp_frame_type, +}; + + static void ao_lisp_mark_busy(void) { int i; memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy)); + memset(ao_lisp_cons, '\0', sizeof (ao_lisp_cons)); + ao_lisp_cons_noted = 0; DBG("mark\n"); for (i = 0; i < AO_LISP_ROOT; i++) { if (ao_lisp_root[i].type) { void **a = ao_lisp_root[i].addr, *v; if (a && (v = *a)) { - DBG("root %p\n", v); + DBG("root %d\n", DBG_OFFSET(v)); ao_lisp_mark(ao_lisp_root[i].type, v); } } else { ao_poly *a = (ao_poly *) ao_lisp_root[i].addr, p; if (a && (p = *a)) { - DBG("root %04x\n", p); - ao_lisp_poly_mark(p); + DBG("root 0x%04x\n", p); + ao_lisp_poly_mark(p, 0); + } + } + } + while (ao_lisp_cons_noted) { + memcpy(ao_lisp_cons_last, ao_lisp_cons, sizeof (ao_lisp_cons)); + memset(ao_lisp_cons, '\0', sizeof (ao_lisp_cons)); + ao_lisp_cons_noted = 0; + for (i = 0; i < AO_LISP_POOL; i += 4) { + if (busy(ao_lisp_cons_last, i)) { + void *v = ao_lisp_pool + i; + DBG("cons %d\n", DBG_OFFSET(v)); + ao_lisp_mark(&ao_lisp_cons_type, v); } } } @@ -274,6 +333,10 @@ ao_lisp_collect(void) abort(); clear_object(ao_lisp_busy, move_old, move_size); mark_object(ao_lisp_busy, move_new, move_size); + if (busy_object(ao_lisp_cons, move_old)) { + clear_object(ao_lisp_cons, move_old, move_size); + mark_object(ao_lisp_cons, move_new, move_size); + } i += move_size; top += move_size; DUMP_BUSY(); @@ -296,6 +359,24 @@ ao_lisp_mark(const struct ao_lisp_type *type, void *addr) return 0; } +int +ao_lisp_poly_mark(ao_poly p, uint8_t do_note_cons) +{ + uint8_t type = ao_lisp_poly_type(p); + + if (!p) + return 1; + if (type == AO_LISP_CONS && do_note_cons) { + note_cons(ao_lisp_ref(p)); + return 0; + } else { + const struct ao_lisp_type *lisp_type = ao_lisp_types[ao_lisp_poly_type(p)]; + if (lisp_type) + return ao_lisp_mark(lisp_type, ao_lisp_ref(p)); + return 1; + } +} + int ao_lisp_mark_memory(void *addr, int size) { @@ -348,7 +429,7 @@ ao_lisp_move(const struct ao_lisp_type *type, void **ref) return 1; #endif DBG_MOVE("object %d\n", DBG_OFFSET(addr)); - if (a < ao_lisp_pool || ao_lisp_pool + AO_LISP_POOL <= a) + if (!AO_LISP_IS_POOL(a)) abort(); DBG_MOVE_IN(); addr = check_move(addr, size); @@ -389,6 +470,47 @@ ao_lisp_move_memory(void **ref, int size) return 0; } +int +ao_lisp_poly_move(ao_poly *ref, uint8_t do_note_cons) +{ + uint8_t type; + ao_poly p = *ref; + const struct ao_lisp_type *lisp_type; + int ret; + void *addr; + + if (!p) + return 1; + + type = ao_lisp_poly_base_type(p); + addr = ao_lisp_ref(p); + if (type == AO_LISP_CONS && do_note_cons) { + note_cons(addr); + addr = check_move(addr, sizeof (struct ao_lisp_cons)); + ret = 1; + } else { + + if (type == AO_LISP_OTHER) + type = ao_lisp_other_type(ao_lisp_move_map(ao_lisp_poly_other(p))); + + if (type >= AO_LISP_NUM_TYPE) + abort(); + + lisp_type = ao_lisp_types[type]; + if (!lisp_type) + return 1; + ret = ao_lisp_move(lisp_type, &addr); + } + + if (addr != ao_lisp_ref(p)) { + ao_poly np = ao_lisp_poly(addr, p & AO_LISP_TYPE_MASK); + DBG("poly %d moved %04x -> %04x\n", + type, p, np); + *ref = np; + } + return ret; +} + #ifdef DBG_POOL static int AO_LISP_POOL_CUR = AO_LISP_POOL / 8; diff --git a/src/lisp/ao_lisp_prim.c b/src/lisp/ao_lisp_prim.c index 82386a83..3c081ee8 100644 --- a/src/lisp/ao_lisp_prim.c +++ b/src/lisp/ao_lisp_prim.c @@ -76,54 +76,3 @@ ao_lisp_poly_patom(ao_poly p) f->patom(p); } -static const struct ao_lisp_type const *ao_lisp_types[AO_LISP_NUM_TYPE] = { - [AO_LISP_CONS] = &ao_lisp_cons_type, - [AO_LISP_INT] = NULL, - [AO_LISP_STRING] = &ao_lisp_string_type, - [AO_LISP_OTHER] = (void *) 0x1, - [AO_LISP_ATOM] = &ao_lisp_atom_type, - [AO_LISP_BUILTIN] = &ao_lisp_builtin_type, - [AO_LISP_FRAME] = &ao_lisp_frame_type, -}; - -int -ao_lisp_poly_mark(ao_poly p) -{ - const struct ao_lisp_type *lisp_type = ao_lisp_types[ao_lisp_poly_type(p)]; - if (lisp_type) - return ao_lisp_mark(lisp_type, ao_lisp_ref(p)); - return 1; -} - -int -ao_lisp_poly_move(ao_poly *ref) -{ - uint8_t type; - ao_poly p = *ref; - const struct ao_lisp_type *lisp_type; - int ret; - void *addr; - - if (!p) - return 1; - - type = p & AO_LISP_TYPE_MASK; - if (type == AO_LISP_OTHER) - type = ao_lisp_other_type(ao_lisp_move_map(ao_lisp_poly_other(p))); - - if (type >= AO_LISP_NUM_TYPE) - abort(); - - lisp_type = ao_lisp_types[type]; - if (!lisp_type) - return 1; - addr = ao_lisp_ref(p); - ret = ao_lisp_move(lisp_type, &addr); - if (addr != ao_lisp_ref(p)) { - ao_poly np = ao_lisp_poly(addr, p & AO_LISP_TYPE_MASK); - DBG("poly %d moved %04x -> %04x\n", - type, p, np); - *ref = np; - } - return ret; -} -- cgit v1.2.3 From cb4cdb115ad83ae0d75eb58e68f561d20279f027 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 6 Nov 2016 21:47:31 -0800 Subject: altos/lambdakey-v1.0: Tweak memory allocations With non-recursive GC, more memory is available for the heap Signed-off-by: Keith Packard --- src/lambdakey-v1.0/ao_pins.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lambdakey-v1.0/ao_pins.h b/src/lambdakey-v1.0/ao_pins.h index 4da638b9..5a840f13 100644 --- a/src/lambdakey-v1.0/ao_pins.h +++ b/src/lambdakey-v1.0/ao_pins.h @@ -25,8 +25,8 @@ #define AO_LED_RED (1 << LED_PIN_RED) #define AO_LED_PANIC AO_LED_RED #define AO_CMD_LEN 128 -#define AO_LISP_POOL 1536 -#define AO_STACK_SIZE 2048 +#define AO_LISP_POOL 2560 +#define AO_STACK_SIZE 1024 #define LEDS_AVAILABLE (AO_LED_RED) -- cgit v1.2.3 From 794718abc62f4610495fe2bd535a2b67bc46573c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 9 Nov 2016 09:14:50 -0800 Subject: altos/lisp: working on lexical scoping Not working yet Signed-off-by: Keith Packard --- src/lisp/Makefile | 4 +- src/lisp/ao_lisp.h | 147 ++++++++- src/lisp/ao_lisp_atom.c | 4 +- src/lisp/ao_lisp_builtin.c | 96 +++++- src/lisp/ao_lisp_const.lisp | 136 +++++++- src/lisp/ao_lisp_error.c | 81 +++++ src/lisp/ao_lisp_eval.c | 730 +++++++++++++++++++++--------------------- src/lisp/ao_lisp_frame.c | 21 ++ src/lisp/ao_lisp_make_const.c | 85 +++-- src/lisp/ao_lisp_mem.c | 1 + src/lisp/ao_lisp_prim.c | 10 +- src/test/Makefile | 2 +- 12 files changed, 876 insertions(+), 441 deletions(-) (limited to 'src') diff --git a/src/lisp/Makefile b/src/lisp/Makefile index be19b432..f7edbe41 100644 --- a/src/lisp/Makefile +++ b/src/lisp/Makefile @@ -18,7 +18,9 @@ SRCS=\ ao_lisp_builtin.c \ ao_lisp_read.c \ ao_lisp_frame.c \ - ao_lisp_error.c + ao_lisp_lambda.c \ + ao_lisp_eval.c \ + ao_lisp_error.c OBJS=$(SRCS:.c=.o) diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 17f1e0f5..6a35d8ce 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -42,7 +42,9 @@ extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST]; #define _ao_lisp_atom_car _atom("car") #define _ao_lisp_atom_cdr _atom("cdr") #define _ao_lisp_atom_cons _atom("cons") +#define _ao_lisp_atom_last _atom("last") #define _ao_lisp_atom_cond _atom("cond") +#define _ao_lisp_atom_lambda _atom("lambda") #else #include "ao_lisp_const.h" #ifndef AO_LISP_POOL @@ -66,7 +68,8 @@ extern uint8_t ao_lisp_pool[AO_LISP_POOL]; #define AO_LISP_ATOM 4 #define AO_LISP_BUILTIN 5 #define AO_LISP_FRAME 6 -#define AO_LISP_NUM_TYPE 7 +#define AO_LISP_LAMBDA 7 +#define AO_LISP_NUM_TYPE 8 #define AO_LISP_NIL 0 @@ -114,8 +117,8 @@ ao_lisp_poly(const void *addr, ao_poly type) { } struct ao_lisp_type { - void (*mark)(void *addr); int (*size)(void *addr); + void (*mark)(void *addr); void (*move)(void *addr); }; @@ -153,10 +156,47 @@ ao_lisp_frame_poly(struct ao_lisp_frame *frame) { return ao_lisp_poly(frame, AO_LISP_OTHER); } -#define AO_LISP_LAMBDA 0 -#define AO_LISP_NLAMBDA 1 -#define AO_LISP_MACRO 2 -#define AO_LISP_LEXPR 3 +struct ao_lisp_stack { + ao_poly prev; + uint8_t state; + uint8_t macro; + ao_poly sexprs; + ao_poly values; + ao_poly values_tail; + ao_poly frame; + ao_poly macro_frame; + ao_poly list; +}; + +enum eval_state { + eval_sexpr, + eval_val, + eval_formal, + eval_exec, + eval_lambda_done, + eval_cond, + eval_cond_test +}; + +static inline struct ao_lisp_stack * +ao_lisp_poly_stack(ao_poly p) +{ + return ao_lisp_ref(p); +} + +static inline ao_poly +ao_lisp_stack_poly(struct ao_lisp_stack *stack) +{ + return ao_lisp_poly(stack, AO_LISP_OTHER); +} + +extern struct ao_lisp_stack *ao_lisp_stack; +extern ao_poly ao_lisp_v; + +#define AO_LISP_FUNC_LAMBDA 0 +#define AO_LISP_FUNC_NLAMBDA 1 +#define AO_LISP_FUNC_MACRO 2 +#define AO_LISP_FUNC_LEXPR 3 struct ao_lisp_builtin { uint8_t type; @@ -165,9 +205,14 @@ struct ao_lisp_builtin { }; enum ao_lisp_builtin_id { + builtin_lambda, + builtin_lexpr, + builtin_nlambda, + builtin_macro, builtin_car, builtin_cdr, builtin_cons, + builtin_last, builtin_quote, builtin_set, builtin_setq, @@ -184,7 +229,7 @@ enum ao_lisp_builtin_id { builtin_greater, builtin_less_equal, builtin_greater_equal, - builtin_last + _builtin_last }; typedef ao_poly (*ao_lisp_func_t)(struct ao_lisp_cons *cons); @@ -197,6 +242,25 @@ ao_lisp_func(struct ao_lisp_builtin *b) return ao_lisp_builtins[b->func]; } +struct ao_lisp_lambda { + uint8_t type; + uint8_t args; + ao_poly code; + ao_poly frame; +}; + +static inline struct ao_lisp_lambda * +ao_lisp_poly_lambda(ao_poly poly) +{ + return ao_lisp_ref(poly); +} + +static inline ao_poly +ao_lisp_lambda_poly(struct ao_lisp_lambda *lambda) +{ + return ao_lisp_poly(lambda, AO_LISP_OTHER); +} + static inline void * ao_lisp_poly_other(ao_poly poly) { return ao_lisp_ref(poly); @@ -360,9 +424,9 @@ ao_lisp_string_patom(ao_poly s); /* atom */ extern const struct ao_lisp_type ao_lisp_atom_type; -extern struct ao_lisp_atom *ao_lisp_atoms; - -extern struct ao_lisp_frame *ao_lisp_frame_current; +extern struct ao_lisp_atom *ao_lisp_atoms; +extern struct ao_lisp_frame *ao_lisp_frame_global; +extern struct ao_lisp_frame *ao_lisp_frame_current; void ao_lisp_atom_print(ao_poly a); @@ -420,6 +484,9 @@ ao_lisp_check_argt(ao_poly name, struct ao_lisp_cons *cons, int argc, int type, ao_poly ao_lisp_arg(struct ao_lisp_cons *cons, int argc); +char * +ao_lisp_args_name(uint8_t args); + /* read */ ao_poly ao_lisp_read(void); @@ -440,9 +507,69 @@ ao_lisp_frame_new(int num); struct ao_lisp_frame * ao_lisp_frame_add(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val); +void +ao_lisp_frame_print(ao_poly p); + +/* lambda */ +extern const struct ao_lisp_type ao_lisp_lambda_type; + +struct ao_lisp_lambda * +ao_lisp_lambda_new(ao_poly cons); + +void +ao_lisp_lambda_print(ao_poly lambda); + +ao_poly +ao_lisp_lambda(struct ao_lisp_cons *cons); + +ao_poly +ao_lisp_lexpr(struct ao_lisp_cons *cons); + +ao_poly +ao_lisp_nlambda(struct ao_lisp_cons *cons); + +ao_poly +ao_lisp_macro(struct ao_lisp_cons *cons); + +ao_poly +ao_lisp_lambda_eval(struct ao_lisp_lambda *lambda, + struct ao_lisp_cons *cons); + /* error */ +void +ao_lisp_stack_print(void); + ao_poly ao_lisp_error(int error, char *format, ...); +/* debugging macros */ + +#if DBG_EVAL +#define DBG_CODE 1 +int ao_lisp_stack_depth; +#define DBG_DO(a) a +#define DBG_INDENT() do { int _s; for(_s = 0; _s < ao_lisp_stack_depth; _s++) printf(" "); } while(0) +#define DBG_IN() (++ao_lisp_stack_depth) +#define DBG_OUT() (--ao_lisp_stack_depth) +#define DBG_RESET() (ao_lisp_stack_depth = 0) +#define DBG(...) printf(__VA_ARGS__) +#define DBGI(...) do { DBG("%4d: ", __LINE__); DBG_INDENT(); DBG(__VA_ARGS__); } while (0) +#define DBG_CONS(a) ao_lisp_cons_print(ao_lisp_cons_poly(a)) +#define DBG_POLY(a) ao_lisp_poly_print(a) +#define OFFSET(a) ((a) ? (int) ((uint8_t *) a - ao_lisp_pool) : -1) +#define DBG_STACK() ao_lisp_stack_print() +#else +#define DBG_DO(a) +#define DBG_INDENT() +#define DBG_IN() +#define DBG_OUT() +#define DBG(...) +#define DBGI(...) +#define DBG_CONS(a) +#define DBG_POLY(a) +#define DBG_RESET() +#define DBG_STACK() +#endif + #endif /* _AO_LISP_H_ */ diff --git a/src/lisp/ao_lisp_atom.c b/src/lisp/ao_lisp_atom.c index 41ba97f5..d7cb1996 100644 --- a/src/lisp/ao_lisp_atom.c +++ b/src/lisp/ao_lisp_atom.c @@ -89,8 +89,8 @@ ao_lisp_atom_intern(char *name) return atom; } -static struct ao_lisp_frame *ao_lisp_frame_global; -struct ao_lisp_frame *ao_lisp_frame_current; +struct ao_lisp_frame *ao_lisp_frame_global; +struct ao_lisp_frame *ao_lisp_frame_current; static void ao_lisp_atom_init(void) diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index 49b6c37d..c38ba165 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -39,11 +39,71 @@ const struct ao_lisp_type ao_lisp_builtin_type = { .move = builtin_move }; +#ifdef AO_LISP_MAKE_CONST +char *ao_lisp_builtin_name(enum ao_lisp_builtin_id b) { + return "???"; +} +char *ao_lisp_args_name(uint8_t args) { + return "???"; +} +#else +static const ao_poly builtin_names[] = { + [builtin_lambda] = _ao_lisp_atom_lambda, + [builtin_lexpr] = _ao_lisp_atom_lexpr, + [builtin_nlambda] = _ao_lisp_atom_nlambda, + [builtin_macro] = _ao_lisp_atom_macro, + [builtin_car] = _ao_lisp_atom_car, + [builtin_cdr] = _ao_lisp_atom_cdr, + [builtin_cons] = _ao_lisp_atom_cons, + [builtin_last] = _ao_lisp_atom_last, + [builtin_quote] = _ao_lisp_atom_quote, + [builtin_set] = _ao_lisp_atom_set, + [builtin_setq] = _ao_lisp_atom_setq, + [builtin_cond] = _ao_lisp_atom_cond, + [builtin_print] = _ao_lisp_atom_print, + [builtin_patom] = _ao_lisp_atom_patom, + [builtin_plus] = _ao_lisp_atom_2b, + [builtin_minus] = _ao_lisp_atom_2d, + [builtin_times] = _ao_lisp_atom_2a, + [builtin_divide] = _ao_lisp_atom_2f, + [builtin_mod] = _ao_lisp_atom_25, + [builtin_equal] = _ao_lisp_atom_3d, + [builtin_less] = _ao_lisp_atom_3c, + [builtin_greater] = _ao_lisp_atom_3e, + [builtin_less_equal] = _ao_lisp_atom_3c3d, + [builtin_greater_equal] = _ao_lisp_atom_3e3d, +}; + +static char * +ao_lisp_builtin_name(enum ao_lisp_builtin_id b) { + if (0 <= b && b < _builtin_last) + return ao_lisp_poly_atom(builtin_names[b])->name; + return "???"; +} + +static const ao_poly ao_lisp_args_atoms[] = { + [AO_LISP_FUNC_LAMBDA] = _ao_lisp_atom_lambda, + [AO_LISP_FUNC_LEXPR] = _ao_lisp_atom_lexpr, + [AO_LISP_FUNC_NLAMBDA] = _ao_lisp_atom_nlambda, + [AO_LISP_FUNC_MACRO] = _ao_lisp_atom_macro, +}; + +char * +ao_lisp_args_name(uint8_t args) +{ + if (args < sizeof ao_lisp_args_atoms / sizeof ao_lisp_args_atoms[0]) + return ao_lisp_poly_atom(ao_lisp_args_atoms[args])->name; + return "(unknown)"; +} +#endif + void ao_lisp_builtin_print(ao_poly b) { - (void) b; - printf("[builtin]"); + struct ao_lisp_builtin *builtin = ao_lisp_poly_builtin(b); + printf("[builtin %s %s]", + ao_lisp_args_name(builtin->args), + ao_lisp_builtin_name(builtin->func)); } ao_poly @@ -116,6 +176,24 @@ ao_lisp_cons(struct ao_lisp_cons *cons) return ao_lisp_cons_poly(ao_lisp_cons_cons(car, ao_lisp_poly_cons(cdr))); } +ao_poly +ao_lisp_last(struct ao_lisp_cons *cons) +{ + ao_poly l; + if (!ao_lisp_check_argc(_ao_lisp_atom_last, cons, 1, 1)) + return AO_LISP_NIL; + if (!ao_lisp_check_argt(_ao_lisp_atom_last, cons, 0, AO_LISP_CONS, 1)) + return AO_LISP_NIL; + l = ao_lisp_arg(cons, 0); + while (l) { + struct ao_lisp_cons *list = ao_lisp_poly_cons(l); + if (!list->cdr) + return list->car; + l = list->cdr; + } + return AO_LISP_NIL; +} + ao_poly ao_lisp_quote(struct ao_lisp_cons *cons) { @@ -151,15 +229,6 @@ ao_lisp_setq(struct ao_lisp_cons *cons) ao_poly ao_lisp_cond(struct ao_lisp_cons *cons) { - int argc; - struct ao_lisp_cons *arg; - - argc = 0; - for (arg = cons, argc = 0; arg; arg = ao_lisp_poly_cons(arg->cdr), argc++) { - if (ao_lisp_poly_type(arg->car) != AO_LISP_CONS) - return ao_lisp_error(AO_LISP_INVALID, "%s: invalid type for arg %d", - ao_lisp_poly_atom(_ao_lisp_atom_cond)->name, argc); - } ao_lisp_set_cond(cons); return AO_LISP_NIL; } @@ -380,9 +449,14 @@ ao_lisp_greater_equal(struct ao_lisp_cons *cons) } ao_lisp_func_t ao_lisp_builtins[] = { + [builtin_lambda] = ao_lisp_lambda, + [builtin_lexpr] = ao_lisp_lexpr, + [builtin_nlambda] = ao_lisp_nlambda, + [builtin_macro] = ao_lisp_macro, [builtin_car] = ao_lisp_car, [builtin_cdr] = ao_lisp_cdr, [builtin_cons] = ao_lisp_cons, + [builtin_last] = ao_lisp_last, [builtin_quote] = ao_lisp_quote, [builtin_set] = ao_lisp_set, [builtin_setq] = ao_lisp_setq, diff --git a/src/lisp/ao_lisp_const.lisp b/src/lisp/ao_lisp_const.lisp index 5ca89bd4..621fefc4 100644 --- a/src/lisp/ao_lisp_const.lisp +++ b/src/lisp/ao_lisp_const.lisp @@ -1,7 +1,129 @@ -cadr (lambda (l) (car (cdr l))) -caddr (lambda (l) (car (cdr (cdr l)))) -list (lexpr (l) l) -1+ (lambda (x) (+ x 1)) -1- (lambda (x) (- x 1)) -last (lambda (x) (cond ((cdr x) (last (cdr x))) ((car x)))) -prog* (lexpr (l) (last l)) + ; basic list accessors + + +(setq cadr (lambda (l) (car (cdr l)))) +(setq caddr (lambda (l) (car (cdr (cdr l))))) +(setq list (lexpr (l) l)) + + ; evaluate a list of sexprs + +(setq progn (lexpr (l) (last l))) + + ; simple math operators + +(setq 1+ (lambda (x) (+ x 1))) +(setq 1- (lambda (x) (- x 1))) + + ; define a variable without returning the value + +(set 'def (macro (def-param) + (list + 'progn + (list + 'set + (list + 'quote + (car def-param)) + (cadr def-param) + ) + (list + 'quote + (car def-param) + ) + ) + ) + ) + + ; define a set of local + ; variables and then evaluate + ; a list of sexprs + ; + ; (let (var-defines) sexprs) + ; + ; where var-defines are either + ; + ; (name value) + ; + ; or + ; + ; (name) + ; + ; e.g. + ; + ; (let ((x 1) (y)) (setq y (+ x 1)) y) + +(def let (macro (let-param) + ((lambda (vars exprs make-names make-exprs make-nils) + (progn + + ; + ; make the list of names in the let + ; + + (set 'make-names (lambda (vars) + (cond (vars + (cons (car (car vars)) + (make-names (cdr vars)))) + ) + ) + ) + ; + ; the set of expressions is + ; the list of set expressions + ; pre-pended to the + ; expressions to evaluate + ; + (set 'make-exprs (lambda (vars exprs) + (progn + (cond (vars (cons + (list set + (list quote + (car (car vars)) + ) + (cadr (car vars)) + ) + (make-exprs (cdr vars) exprs) + ) + ) + (exprs) + ) + ) + ) + ) + (set 'exprs (make-exprs vars exprs)) + + ; + ; the parameters to the lambda is a list + ; of nils of the right length + ; + (set 'make-nils (lambda (vars) + (cond (vars (cons nil (make-nils (cdr vars)))) + ) + ) + ) + ; + ; build the lambda. + ; + (set 'last-let-value + (cons + (list + 'lambda + (make-names vars) + (cond ((cdr exprs) (cons 'progn exprs)) + ((car exprs)) + ) + ) + (make-nils vars) + ) + ) + ) + + ) + (car let-param) + (cdr let-param) + () + () + () + ) + ) + ) diff --git a/src/lisp/ao_lisp_error.c b/src/lisp/ao_lisp_error.c index ea8111d9..cedc107c 100644 --- a/src/lisp/ao_lisp_error.c +++ b/src/lisp/ao_lisp_error.c @@ -15,6 +15,86 @@ #include "ao_lisp.h" #include +static void +ao_lisp_error_cons(char *name, struct ao_lisp_cons *cons) +{ + int first = 1; + printf("\t\t%s(", name); + if (cons) { + while (cons) { + if (!first) + printf("\t\t "); + else + first = 0; + ao_lisp_poly_print(cons->car); + printf("\n"); + cons = ao_lisp_poly_cons(cons->cdr); + } + printf("\t\t )\n"); + } else + printf(")\n"); +} + +static void tabs(int indent) +{ + while (indent--) + printf("\t"); +} + +static void +ao_lisp_error_frame(int indent, char *name, struct ao_lisp_frame *frame) +{ + int f; + + tabs(indent); + printf ("%s{", name); + if (frame) { + for (f = 0; f < frame->num; f++) { + if (f != 0) { + tabs(indent); + printf(" "); + } + ao_lisp_poly_print(frame->vals[f].atom); + printf(" = "); + ao_lisp_poly_print(frame->vals[f].val); + printf("\n"); + } + if (frame->next) + ao_lisp_error_frame(indent + 1, "next: ", ao_lisp_poly_frame(frame->next)); + } + tabs(indent); + printf(" }\n"); +} + +static const char *state_names[] = { + "sexpr", + "val", + "formal", + "exec", + "cond", + "cond_test", +}; + +void +ao_lisp_stack_print(void) +{ + struct ao_lisp_stack *s; + printf("Value: "); ao_lisp_poly_print(ao_lisp_v); printf("\n"); + ao_lisp_error_frame(0, "Frame: ", ao_lisp_frame_current); + printf("Stack:\n"); + for (s = ao_lisp_stack; s; s = ao_lisp_poly_stack(s->prev)) { + printf("\t[\n"); + printf("\t\texpr: "); ao_lisp_poly_print(s->list); printf("\n"); + printf("\t\tstate: %s\n", state_names[s->state]); + printf("\t\tmacro: %s\n", s->macro ? "true" : "false"); + ao_lisp_error_cons ("sexprs: ", ao_lisp_poly_cons(s->sexprs)); + ao_lisp_error_cons ("values: ", ao_lisp_poly_cons(s->values)); + ao_lisp_error_frame(2, "frame: ", ao_lisp_poly_frame(s->frame)); + ao_lisp_error_frame(2, "mframe: ", ao_lisp_poly_frame(s->macro_frame)); + printf("\t]\n"); + } +} + ao_poly ao_lisp_error(int error, char *format, ...) { @@ -25,5 +105,6 @@ ao_lisp_error(int error, char *format, ...) vprintf(format, args); va_end(args); printf("\n"); + ao_lisp_stack_print(); return AO_LISP_NIL; } diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index a5c74250..f4196219 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -12,60 +12,9 @@ * General Public License for more details. */ +#define DBG_EVAL 1 #include "ao_lisp.h" - -#if 0 -#define DBG_CODE 1 -static int stack_depth; -#define DBG_INDENT() do { int _s; for(_s = 0; _s < stack_depth; _s++) printf(" "); } while(0) -#define DBG_IN() (++stack_depth) -#define DBG_OUT() (--stack_depth) -#define DBG(...) printf(__VA_ARGS__) -#define DBGI(...) do { DBG_INDENT(); DBG("%4d: ", __LINE__); DBG(__VA_ARGS__); } while (0) -#define DBG_CONS(a) ao_lisp_cons_print(ao_lisp_cons_poly(a)) -#define DBG_POLY(a) ao_lisp_poly_print(a) -#define OFFSET(a) ((a) ? (int) ((uint8_t *) a - ao_lisp_pool) : -1) -#else -#define DBG_INDENT() -#define DBG_IN() -#define DBG_OUT() -#define DBG(...) -#define DBGI(...) -#define DBG_CONS(a) -#define DBG_POLY(a) -#endif - -enum eval_state { - eval_sexpr, - eval_val, - eval_formal, - eval_exec, - eval_exec_direct, - eval_cond, - eval_cond_test -}; - -struct ao_lisp_stack { - ao_poly prev; - uint8_t state; - uint8_t macro; - ao_poly actuals; - ao_poly formals; - ao_poly formals_tail; - ao_poly frame; -}; - -static struct ao_lisp_stack * -ao_lisp_poly_stack(ao_poly p) -{ - return ao_lisp_ref(p); -} - -static ao_poly -ao_lisp_stack_poly(struct ao_lisp_stack *stack) -{ - return ao_lisp_poly(stack, AO_LISP_OTHER); -} +#include static int stack_size(void *addr) @@ -79,10 +28,11 @@ stack_mark(void *addr) { struct ao_lisp_stack *stack = addr; for (;;) { - ao_lisp_poly_mark(stack->actuals, 0); - ao_lisp_poly_mark(stack->formals, 0); - /* no need to mark formals_tail */ + ao_lisp_poly_mark(stack->sexprs, 0); + ao_lisp_poly_mark(stack->values, 0); + /* no need to mark values_tail */ ao_lisp_poly_mark(stack->frame, 0); + ao_lisp_poly_mark(stack->macro_frame, 0); stack = ao_lisp_poly_stack(stack->prev); if (ao_lisp_mark_memory(stack, sizeof (struct ao_lisp_stack))) break; @@ -91,29 +41,6 @@ stack_mark(void *addr) static const struct ao_lisp_type ao_lisp_stack_type; -#if DBG_CODE -static void -stack_validate_tail(struct ao_lisp_stack *stack) -{ - struct ao_lisp_cons *head = ao_lisp_poly_cons(stack->formals); - struct ao_lisp_cons *tail = ao_lisp_poly_cons(stack->formals_tail); - struct ao_lisp_cons *cons; - for (cons = head; cons && cons->cdr && cons != tail; cons = ao_lisp_poly_cons(cons->cdr)) - ; - if (cons != tail || (tail && tail->cdr)) { - if (!tail) { - printf("tail null\n"); - } else { - printf("tail validate fail head %d actual %d recorded %d\n", - OFFSET(head), OFFSET(cons), OFFSET(tail)); - abort(); - } - } -} -#else -#define stack_validate_tail(s) -#endif - static void stack_move(void *addr) { @@ -122,15 +49,15 @@ stack_move(void *addr) while (stack) { void *prev; int ret; - (void) ao_lisp_poly_move(&stack->actuals, 0); - (void) ao_lisp_poly_move(&stack->formals, 0); - (void) ao_lisp_poly_move(&stack->formals_tail, 0); + (void) ao_lisp_poly_move(&stack->sexprs, 0); + (void) ao_lisp_poly_move(&stack->values, 0); + (void) ao_lisp_poly_move(&stack->values_tail, 0); (void) ao_lisp_poly_move(&stack->frame, 0); + (void) ao_lisp_poly_move(&stack->macro_frame, 0); prev = ao_lisp_poly_stack(stack->prev); ret = ao_lisp_move(&ao_lisp_stack_type, &prev); if (prev != ao_lisp_poly_stack(stack->prev)) stack->prev = ao_lisp_stack_poly(prev); - stack_validate_tail(stack); if (ret) break; stack = ao_lisp_poly_stack(stack->prev); @@ -143,199 +70,421 @@ static const struct ao_lisp_type ao_lisp_stack_type = { .move = stack_move }; -static struct ao_lisp_stack *ao_lisp_stack; -static ao_poly ao_lisp_v; -static uint8_t been_here; - -#if DBG_CODE -static void -stack_validate_tails(void) -{ - struct ao_lisp_stack *stack; - - for (stack = ao_lisp_stack; stack; stack = ao_lisp_poly_stack(stack->prev)) - stack_validate_tail(stack); -} -#else -#define stack_validate_tails(s) -#endif +struct ao_lisp_stack *ao_lisp_stack; +ao_poly ao_lisp_v; ao_poly ao_lisp_set_cond(struct ao_lisp_cons *c) { ao_lisp_stack->state = eval_cond; - ao_lisp_stack->actuals = ao_lisp_cons_poly(c); + ao_lisp_stack->sexprs = ao_lisp_cons_poly(c); return AO_LISP_NIL; } -void +static void ao_lisp_stack_reset(struct ao_lisp_stack *stack) { stack->state = eval_sexpr; stack->macro = 0; - stack->actuals = AO_LISP_NIL; - stack->formals = AO_LISP_NIL; - stack->formals_tail = AO_LISP_NIL; - stack->frame = ao_lisp_frame_poly(ao_lisp_frame_current); - stack_validate_tails(); + stack->sexprs = AO_LISP_NIL; + stack->values = AO_LISP_NIL; + stack->values_tail = AO_LISP_NIL; } -int -ao_lisp_stack_push(void) +static void +ao_lisp_frames_dump(void) { - stack_validate_tails(); - if (ao_lisp_stack) { - DBGI("formals "); DBG_POLY(ao_lisp_stack->formals); DBG("\n"); - DBGI("actuals "); DBG_POLY(ao_lisp_stack->actuals); DBG("\n"); + struct ao_lisp_stack *s; + DBGI(".. current frame: "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); + for (s = ao_lisp_stack; s; s = ao_lisp_poly_stack(s->prev)) { + DBGI(".. stack frame: "); DBG_POLY(s->frame); DBG("\n"); + DBGI(".. macro frame: "); DBG_POLY(s->frame); DBG("\n"); } +} + +static int +ao_lisp_stack_push(void) +{ DBGI("stack push\n"); DBG_IN(); struct ao_lisp_stack *stack = ao_lisp_alloc(sizeof (struct ao_lisp_stack)); if (!stack) return 0; stack->prev = ao_lisp_stack_poly(ao_lisp_stack); + stack->frame = ao_lisp_frame_poly(ao_lisp_frame_current); + stack->list = AO_LISP_NIL; ao_lisp_stack = stack; ao_lisp_stack_reset(stack); - stack_validate_tails(); + ao_lisp_frames_dump(); return 1; } -void +static void ao_lisp_stack_pop(void) { if (!ao_lisp_stack) return; - stack_validate_tails(); + ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->frame); + ao_lisp_stack = ao_lisp_poly_stack(ao_lisp_stack->prev); DBG_OUT(); DBGI("stack pop\n"); - ao_lisp_stack = ao_lisp_poly_stack(ao_lisp_stack->prev); - if (ao_lisp_stack) - ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->frame); - else - ao_lisp_frame_current = NULL; - if (ao_lisp_stack) { - DBGI("formals "); DBG_POLY(ao_lisp_stack->formals); DBG("\n"); - DBGI("actuals "); DBG_POLY(ao_lisp_stack->actuals); DBG("\n"); - } + ao_lisp_frames_dump(); } static void ao_lisp_stack_clear(void) { - stack_validate_tails(); ao_lisp_stack = NULL; ao_lisp_frame_current = NULL; + ao_lisp_v = AO_LISP_NIL; } -static ao_poly +static int func_type(ao_poly func) { - struct ao_lisp_cons *cons; - struct ao_lisp_cons *args; - int f; - - DBGI("func type "); DBG_POLY(func); DBG("\n"); if (func == AO_LISP_NIL) return ao_lisp_error(AO_LISP_INVALID, "func is nil"); - if (ao_lisp_poly_type(func) == AO_LISP_BUILTIN) { - struct ao_lisp_builtin *b = ao_lisp_poly_builtin(func); - return b->args; - } else if (ao_lisp_poly_type(func) == AO_LISP_CONS) { - cons = ao_lisp_poly_cons(func); - if (!ao_lisp_check_argc(_ao_lisp_atom_lambda, cons, 3, 3)) - return AO_LISP_NIL; - if (!ao_lisp_check_argt(_ao_lisp_atom_lambda, cons, 0, AO_LISP_ATOM, 0)) - return AO_LISP_NIL; - if (!ao_lisp_check_argt(_ao_lisp_atom_lambda, cons, 1, AO_LISP_CONS, 1)) - return AO_LISP_NIL; - args = ao_lisp_poly_cons(ao_lisp_arg(cons, 1)); - f = 0; - while (args) { - if (ao_lisp_poly_type(args->car) != AO_LISP_ATOM) { - return ao_lisp_error(ao_lisp_arg(cons, 0), "formal %d is not an atom", f); - } - args = ao_lisp_poly_cons(args->cdr); - f++; - } - return ao_lisp_arg(cons, 0); - } else { + switch (ao_lisp_poly_type(func)) { + case AO_LISP_BUILTIN: + return ao_lisp_poly_builtin(func)->args; + case AO_LISP_LAMBDA: + return ao_lisp_poly_lambda(func)->args; + default: ao_lisp_error(AO_LISP_INVALID, "not a func"); - abort(); - return AO_LISP_NIL; + return -1; } } +/* + * Flattened eval to avoid stack issues + */ + +/* + * Evaluate an s-expression + * + * For a list, evaluate all of the elements and + * then execute the resulting function call. + * + * Each element of the list is evaluated in + * a clean stack context. + * + * The current stack state is set to 'formal' so that + * when the evaluation is complete, the value + * will get appended to the values list. + * + * For other types, compute the value directly. + */ + static int -ao_lisp_cons_length(struct ao_lisp_cons *cons) +ao_lisp_eval_sexpr(void) { - int len = 0; - while (cons) { - len++; - cons = ao_lisp_poly_cons(cons->cdr); + DBGI("sexpr: "); DBG_POLY(ao_lisp_v); DBG("\n"); + switch (ao_lisp_poly_type(ao_lisp_v)) { + case AO_LISP_CONS: + if (ao_lisp_v == AO_LISP_NIL) { + if (!ao_lisp_stack->values) { + /* + * empty list evaluates to empty list + */ + ao_lisp_v = AO_LISP_NIL; + ao_lisp_stack->state = eval_val; + } else { + /* + * done with arguments, go execute it + */ + ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->values)->car; + ao_lisp_stack->state = eval_exec; + } + } else { + if (!ao_lisp_stack->values) + ao_lisp_stack->list = ao_lisp_v; + /* + * Evaluate another argument and then switch + * to 'formal' to add the value to the values + * list + */ + ao_lisp_stack->sexprs = ao_lisp_v; + ao_lisp_stack->state = eval_formal; + if (!ao_lisp_stack_push()) + return 0; + /* + * push will reset the state to 'sexpr', which + * will evaluate the expression + */ + ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car; + } + break; + case AO_LISP_ATOM: + DBGI("..frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); + ao_lisp_v = ao_lisp_atom_get(ao_lisp_v); + /* fall through */ + case AO_LISP_INT: + case AO_LISP_STRING: + case AO_LISP_BUILTIN: + case AO_LISP_LAMBDA: + ao_lisp_stack->state = eval_val; + break; } - return len; + DBGI(".. result "); DBG_POLY(ao_lisp_v); DBG("\n"); + return 1; } -static ao_poly -ao_lisp_lambda(struct ao_lisp_cons *cons) +/* + * A value has been computed. + * + * If the value was computed from a macro, + * then we want to reset the current context + * to evaluate the macro result again. + * + * If not a macro, then pop the stack. + * If the stack is empty, we're done. + * Otherwise, the stack will contain + * the next state. + */ + +static int +ao_lisp_eval_val(void) { - ao_poly type; - struct ao_lisp_cons *lambda; - struct ao_lisp_cons *args; - struct ao_lisp_frame *next_frame; - int args_wanted; - int args_provided; + DBGI("val: "); DBG_POLY(ao_lisp_v); DBG("\n"); + if (ao_lisp_stack->macro) { + DBGI("..macro %d\n", ao_lisp_stack->macro); + DBGI("..current frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); + DBGI("..saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n"); + DBGI("..macro frame "); DBG_POLY(ao_lisp_stack->macro_frame); DBG("\n"); + DBGI("..sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); + DBGI("..values "); DBG_POLY(ao_lisp_stack->values); DBG("\n"); + /* + * Re-use the current stack to evaluate + * the value from the macro + */ + ao_lisp_stack->state = eval_sexpr; +// assert(ao_lisp_stack->frame == ao_lisp_stack->macro_frame); + ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->macro_frame); + ao_lisp_stack->frame = ao_lisp_stack->macro_frame; + ao_lisp_stack->macro = 0; + ao_lisp_stack->macro_frame = AO_LISP_NIL; + ao_lisp_stack->sexprs = AO_LISP_NIL; + ao_lisp_stack->values = AO_LISP_NIL; + ao_lisp_stack->values_tail = AO_LISP_NIL; + } else { + /* + * Value computed, pop the stack + * to figure out what to do with the value + */ + ao_lisp_stack_pop(); + } + DBGI("..state %d\n", ao_lisp_stack ? ao_lisp_stack->state : -1); + return 1; +} - lambda = ao_lisp_poly_cons(ao_lisp_arg(cons, 0)); - DBGI("lambda "); DBG_CONS(lambda); DBG("\n"); - type = ao_lisp_arg(lambda, 0); - args = ao_lisp_poly_cons(ao_lisp_arg(lambda, 1)); +/* + * A formal has been computed. + * + * If this is the first formal, then + * check to see if we've got a lamda/lexpr or + * macro/nlambda. + * + * For lambda/lexpr, go compute another formal. + * This will terminate when the sexpr state + * sees nil. + * + * For macro/nlambda, we're done, so move the + * sexprs into the values and go execute it. + */ - args_wanted = ao_lisp_cons_length(args); +static int +ao_lisp_eval_formal(void) +{ + ao_poly formal; - /* Create a frame to hold the variables - */ - if (type == _ao_lisp_atom_lambda) - args_provided = ao_lisp_cons_length(cons) - 1; - else - args_provided = 1; - if (args_wanted != args_provided) - return ao_lisp_error(AO_LISP_INVALID, "need %d args, not %d", args_wanted, args_provided); - next_frame = ao_lisp_frame_new(args_wanted); -// DBGI("new frame %d\n", OFFSET(next_frame)); - switch (type) { - case _ao_lisp_atom_lambda: { - int f; - struct ao_lisp_cons *vals = ao_lisp_poly_cons(cons->cdr); - - for (f = 0; f < args_wanted; f++) { - next_frame->vals[f].atom = args->car; - next_frame->vals[f].val = vals->car; - args = ao_lisp_poly_cons(args->cdr); - vals = ao_lisp_poly_cons(vals->cdr); + DBGI("formal: "); DBG_POLY(ao_lisp_v); DBG("\n"); + + /* Check what kind of function we've got */ + if (!ao_lisp_stack->values) { + switch (func_type(ao_lisp_v)) { + case AO_LISP_FUNC_LAMBDA: + case AO_LISP_FUNC_LEXPR: + DBGI(".. lambda or lexpr\n"); + break; + case AO_LISP_FUNC_MACRO: + ao_lisp_stack->macro = 1; + DBGI(".. macro %d\n", ao_lisp_stack->macro); + DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); + DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n"); + ao_lisp_stack->macro_frame = ao_lisp_stack->frame; + /* fall through ... */ + case AO_LISP_FUNC_NLAMBDA: + DBGI(".. nlambda or macro\n"); + ao_lisp_stack->values = ao_lisp_stack->sexprs; + ao_lisp_stack->values_tail = AO_LISP_NIL; + ao_lisp_stack->state = eval_exec; + return 1; + case -1: + return 0; } - break; } - case _ao_lisp_atom_lexpr: - case _ao_lisp_atom_nlambda: - next_frame->vals[0].atom = args->car; - next_frame->vals[0].val = cons->cdr; + + /* Append formal to list of values */ + formal = ao_lisp_cons_poly(ao_lisp_cons_cons(ao_lisp_v, NULL)); + if (!formal) + return 0; + + if (ao_lisp_stack->values_tail) + ao_lisp_poly_cons(ao_lisp_stack->values_tail)->cdr = formal; + else + ao_lisp_stack->values = formal; + ao_lisp_stack->values_tail = formal; + + DBGI(".. values "); DBG_POLY(ao_lisp_stack->values); DBG("\n"); + + /* + * Step to the next argument, if this is last, then + * 'sexpr' will end up switching to 'exec' + */ + ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr; + + ao_lisp_stack->state = eval_sexpr; + + DBGI(".. "); DBG_POLY(ao_lisp_v); DBG("\n"); + return 1; +} + +/* + * Start executing a function call + * + * Most builtins are easy, just call the function. + * 'cond' is magic; it sticks the list of clauses + * in 'sexprs' and switches to 'cond' state. That + * bit of magic is done in ao_lisp_set_cond. + * + * Lambdas build a new frame to hold the locals and + * then re-use the current stack context to evaluate + * the s-expression from the lambda. + */ + +static int +ao_lisp_eval_exec(void) +{ + ao_poly v; + DBGI("exec: "); DBG_POLY(ao_lisp_v); DBG(" values "); DBG_POLY(ao_lisp_stack->values); DBG ("\n"); + ao_lisp_stack->sexprs = AO_LISP_NIL; + switch (ao_lisp_poly_type(ao_lisp_v)) { + case AO_LISP_BUILTIN: + ao_lisp_stack->state = eval_val; + v = ao_lisp_func(ao_lisp_poly_builtin(ao_lisp_v)) ( + ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->values)->cdr)); + DBG_DO(if (!ao_lisp_exception && ao_lisp_poly_builtin(ao_lisp_v)->func == builtin_set) { + struct ao_lisp_cons *cons = ao_lisp_poly_cons(ao_lisp_stack->values); + ao_poly atom = ao_lisp_arg(cons, 1); + ao_poly val = ao_lisp_arg(cons, 2); + DBGI("set "); DBG_POLY(atom); DBG(" = "); DBG_POLY(val); DBG("\n"); + }); + ao_lisp_v = v; + DBGI(".. result "); DBG_POLY(ao_lisp_v); DBG ("\n"); + DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); break; - case _ao_lisp_atom_macro: - next_frame->vals[0].atom = args->car; - next_frame->vals[0].val = ao_lisp_cons_poly(cons); + case AO_LISP_LAMBDA: + ao_lisp_stack->state = eval_sexpr; + DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); + ao_lisp_v = ao_lisp_lambda_eval(ao_lisp_poly_lambda(ao_lisp_v), + ao_lisp_poly_cons(ao_lisp_stack->values)); + DBGI(".. sexpr "); DBG_POLY(ao_lisp_v); DBG("\n"); + DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); break; } - next_frame->next = ao_lisp_frame_poly(ao_lisp_frame_current); - ao_lisp_frame_current = next_frame; - ao_lisp_stack->frame = ao_lisp_frame_poly(next_frame); - return ao_lisp_arg(lambda, 2); + ao_lisp_stack->values = AO_LISP_NIL; + ao_lisp_stack->values_tail = AO_LISP_NIL; + return 1; } +static int +ao_lisp_eval_lambda_done(void) +{ + DBGI("lambda_done: "); DBG_POLY(ao_lisp_v); DBG("\n"); + DBG_STACK(); + return 1; +} + +/* + * Start evaluating the next cond clause + * + * If the list of clauses is empty, then + * the result of the cond is nil. + * + * Otherwise, set the current stack state to 'cond_test' and create a + * new stack context to evaluate the test s-expression. Once that's + * complete, we'll land in 'cond_test' to finish the clause. + */ +static int +ao_lisp_eval_cond(void) +{ + DBGI("cond: "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); + DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); + DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n"); + if (!ao_lisp_stack->sexprs) { + ao_lisp_v = AO_LISP_NIL; + ao_lisp_stack->state = eval_val; + } else { + ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car; + if (!ao_lisp_v || ao_lisp_poly_type(ao_lisp_v) != AO_LISP_CONS) { + ao_lisp_error(AO_LISP_INVALID, "invalid cond clause"); + return 0; + } + ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car; + ao_lisp_stack->state = eval_cond_test; + if (!ao_lisp_stack_push()) + return 0; + ao_lisp_stack->state = eval_sexpr; + } + return 1; +} + +/* + * Finish a cond clause. + * + * Check the value from the test expression, if + * non-nil, then set up to evaluate the value expression. + * + * Otherwise, step to the next clause and go back to the 'cond' + * state + */ +static int +ao_lisp_eval_cond_test(void) +{ + DBGI("cond_test: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); + DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); + DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n"); + if (ao_lisp_v) { + struct ao_lisp_cons *car = ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car); + struct ao_lisp_cons *c = ao_lisp_poly_cons(car->cdr); + + ao_lisp_stack->state = eval_val; + if (c) { + ao_lisp_v = c->car; + if (!ao_lisp_stack_push()) + return 0; + } + } else { + ao_lisp_stack->sexprs = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr; + DBGI("next cond: "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); + ao_lisp_stack->state = eval_cond; + } + return 1; +} + +static int (*const evals[])(void) = { + [eval_sexpr] = ao_lisp_eval_sexpr, + [eval_val] = ao_lisp_eval_val, + [eval_formal] = ao_lisp_eval_formal, + [eval_exec] = ao_lisp_eval_exec, + [eval_cond] = ao_lisp_eval_cond, + [eval_cond_test] = ao_lisp_eval_cond_test, +}; + ao_poly ao_lisp_eval(ao_poly _v) { - ao_poly formal; + static uint8_t been_here; ao_lisp_v = _v; if (!been_here) { @@ -345,165 +494,16 @@ ao_lisp_eval(ao_poly _v) } if (!ao_lisp_stack_push()) - goto bail; - - for (;;) { - if (ao_lisp_exception) - goto bail; - switch (ao_lisp_stack->state) { - case eval_sexpr: - DBGI("sexpr: "); DBG_POLY(ao_lisp_v); DBG("\n"); - switch (ao_lisp_poly_type(ao_lisp_v)) { - case AO_LISP_CONS: - if (ao_lisp_v == AO_LISP_NIL) { - ao_lisp_stack->state = eval_exec; - break; - } - ao_lisp_stack->actuals = ao_lisp_v; - DBGI("actuals now "); DBG_POLY(ao_lisp_v); DBG("\n"); - ao_lisp_stack->state = eval_formal; - if (!ao_lisp_stack_push()) - goto bail; - ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car; - stack_validate_tails(); - break; - case AO_LISP_ATOM: - ao_lisp_v = ao_lisp_atom_get(ao_lisp_v); - /* fall through */ - case AO_LISP_INT: - case AO_LISP_STRING: - case AO_LISP_BUILTIN: - ao_lisp_stack->state = eval_val; - break; - } - break; - case eval_val: - DBGI("val: "); DBG_POLY(ao_lisp_v); DBG("\n"); - ao_lisp_stack_pop(); - if (!ao_lisp_stack) - return ao_lisp_v; - DBGI("..state %d\n", ao_lisp_stack->state); - break; - - case eval_formal: - /* Check what kind of function we've got */ - if (!ao_lisp_stack->formals) { - switch (func_type(ao_lisp_v)) { - case AO_LISP_LAMBDA: - case _ao_lisp_atom_lambda: - case AO_LISP_LEXPR: - case _ao_lisp_atom_lexpr: - DBGI(".. lambda or lexpr\n"); - break; - case AO_LISP_MACRO: - case _ao_lisp_atom_macro: - ao_lisp_stack->macro = 1; - case AO_LISP_NLAMBDA: - case _ao_lisp_atom_nlambda: - DBGI(".. nlambda or macro\n"); - ao_lisp_stack->formals = ao_lisp_stack->actuals; - ao_lisp_stack->formals_tail = AO_LISP_NIL; - ao_lisp_stack->state = eval_exec_direct; - stack_validate_tails(); - break; - } - if (ao_lisp_stack->state == eval_exec_direct) - break; - } - - DBGI("add formal "); DBG_POLY(ao_lisp_v); DBG("\n"); - stack_validate_tails(); - formal = ao_lisp_cons_poly(ao_lisp_cons_cons(ao_lisp_v, NULL)); - stack_validate_tails(); - if (!formal) - goto bail; - - if (ao_lisp_stack->formals_tail) - ao_lisp_poly_cons(ao_lisp_stack->formals_tail)->cdr = formal; - else - ao_lisp_stack->formals = formal; - ao_lisp_stack->formals_tail = formal; - - DBGI("formals now "); DBG_POLY(ao_lisp_stack->formals); DBG("\n"); - - ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->actuals)->cdr; - - stack_validate_tails(); - ao_lisp_stack->state = eval_sexpr; + return AO_LISP_NIL; - break; - case eval_exec: - if (!ao_lisp_stack->formals) { - ao_lisp_v = AO_LISP_NIL; - ao_lisp_stack->state = eval_val; - break; - } - ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->formals)->car; - case eval_exec_direct: - DBGI("exec: macro %d ", ao_lisp_stack->macro); DBG_POLY(ao_lisp_v); DBG(" formals "); DBG_POLY(ao_lisp_stack->formals); DBG ("\n"); - if (ao_lisp_poly_type(ao_lisp_v) == AO_LISP_BUILTIN) { - stack_validate_tails(); - struct ao_lisp_builtin *b = ao_lisp_poly_builtin(ao_lisp_v); - stack_validate_tails(); - struct ao_lisp_cons *f = ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->formals)->cdr); - - DBGI(".. builtin formals "); DBG_CONS(f); DBG("\n"); - stack_validate_tails(); - if (ao_lisp_stack->macro) - ao_lisp_stack->state = eval_sexpr; - else - ao_lisp_stack->state = eval_val; - ao_lisp_stack->macro = 0; - ao_lisp_stack->actuals = ao_lisp_stack->formals = ao_lisp_stack->formals_tail = AO_LISP_NIL; - ao_lisp_v = ao_lisp_func(b) (f); - DBGI("builtin result:"); DBG_POLY(ao_lisp_v); DBG ("\n"); - if (ao_lisp_exception) - goto bail; - break; - } else { - ao_lisp_v = ao_lisp_lambda(ao_lisp_poly_cons(ao_lisp_stack->formals)); - ao_lisp_stack_reset(ao_lisp_stack); - } - break; - case eval_cond: - DBGI("cond: "); DBG_POLY(ao_lisp_stack->actuals); DBG("\n"); - if (!ao_lisp_stack->actuals) { - ao_lisp_v = AO_LISP_NIL; - ao_lisp_stack->state = eval_val; - } else { - ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->actuals)->car; - if (!ao_lisp_v || ao_lisp_poly_type(ao_lisp_v) != AO_LISP_CONS) { - ao_lisp_error(AO_LISP_INVALID, "invalid cond clause"); - goto bail; - } - ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car; - ao_lisp_stack->state = eval_cond_test; - stack_validate_tails(); - ao_lisp_stack_push(); - stack_validate_tails(); - ao_lisp_stack->state = eval_sexpr; - } - break; - case eval_cond_test: - DBGI("cond_test: "); DBG_POLY(ao_lisp_v); DBG(" actuals "); DBG_POLY(ao_lisp_stack->actuals); DBG("\n"); - if (ao_lisp_v) { - struct ao_lisp_cons *car = ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->actuals)->car); - struct ao_lisp_cons *c = ao_lisp_poly_cons(car->cdr); - if (c) { - ao_lisp_v = c->car; - ao_lisp_stack->state = eval_sexpr; - } else { - ao_lisp_stack->state = eval_val; - } - } else { - ao_lisp_stack->actuals = ao_lisp_poly_cons(ao_lisp_stack->actuals)->cdr; - DBGI("actuals now "); DBG_POLY(ao_lisp_stack->actuals); DBG("\n"); - ao_lisp_stack->state = eval_cond; - } - break; + while (ao_lisp_stack) { +// DBG_STACK(); + if (!(*evals[ao_lisp_stack->state])() || ao_lisp_exception) { + ao_lisp_stack_clear(); + return AO_LISP_NIL; } } -bail: - ao_lisp_stack_clear(); - return AO_LISP_NIL; + DBG_DO(if (ao_lisp_frame_current) {DBGI("frame left as "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n");}); + ao_lisp_frame_current = NULL; + return ao_lisp_v; } diff --git a/src/lisp/ao_lisp_frame.c b/src/lisp/ao_lisp_frame.c index 8791c4de..7978f20a 100644 --- a/src/lisp/ao_lisp_frame.c +++ b/src/lisp/ao_lisp_frame.c @@ -100,6 +100,27 @@ const struct ao_lisp_type ao_lisp_frame_type = { .move = frame_move }; +void +ao_lisp_frame_print(ao_poly p) +{ + struct ao_lisp_frame *frame = ao_lisp_poly_frame(p); + int f; + + printf ("{"); + if (frame) { + for (f = 0; f < frame->num; f++) { + if (f != 0) + printf(", "); + ao_lisp_poly_print(frame->vals[f].atom); + printf(" = "); + ao_lisp_poly_print(frame->vals[f].val); + } + if (frame->next) + ao_lisp_poly_print(frame->next); + } + printf("}"); +} + ao_poly * ao_lisp_frame_ref(struct ao_lisp_frame *frame, ao_poly atom) { diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index f2e3cea1..501052b9 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -33,34 +33,32 @@ struct builtin_func { }; struct builtin_func funcs[] = { - "car", AO_LISP_LEXPR, builtin_car, - "cdr", AO_LISP_LEXPR, builtin_cdr, - "cons", AO_LISP_LEXPR, builtin_cons, - "quote", AO_LISP_NLAMBDA,builtin_quote, - "set", AO_LISP_LEXPR, builtin_set, - "setq", AO_LISP_MACRO, builtin_setq, - "cond", AO_LISP_NLAMBDA,builtin_cond, - "print", AO_LISP_LEXPR, builtin_print, - "patom", AO_LISP_LEXPR, builtin_patom, - "+", AO_LISP_LEXPR, builtin_plus, - "-", AO_LISP_LEXPR, builtin_minus, - "*", AO_LISP_LEXPR, builtin_times, - "/", AO_LISP_LEXPR, builtin_divide, - "%", AO_LISP_LEXPR, builtin_mod, - "=", AO_LISP_LEXPR, builtin_equal, - "<", AO_LISP_LEXPR, builtin_less, - ">", AO_LISP_LEXPR, builtin_greater, - "<=", AO_LISP_LEXPR, builtin_less_equal, - ">=", AO_LISP_LEXPR, builtin_greater_equal, + "lambda", AO_LISP_FUNC_NLAMBDA, builtin_lambda, + "lexpr", AO_LISP_FUNC_NLAMBDA, builtin_lexpr, + "nlambda", AO_LISP_FUNC_NLAMBDA, builtin_nlambda, + "macro", AO_LISP_FUNC_NLAMBDA, builtin_macro, + "car", AO_LISP_FUNC_LAMBDA, builtin_car, + "cdr", AO_LISP_FUNC_LAMBDA, builtin_cdr, + "cons", AO_LISP_FUNC_LAMBDA, builtin_cons, + "last", AO_LISP_FUNC_LAMBDA, builtin_last, + "quote", AO_LISP_FUNC_NLAMBDA, builtin_quote, + "set", AO_LISP_FUNC_LAMBDA, builtin_set, + "setq", AO_LISP_FUNC_MACRO, builtin_setq, + "cond", AO_LISP_FUNC_NLAMBDA, builtin_cond, + "print", AO_LISP_FUNC_LEXPR, builtin_print, + "patom", AO_LISP_FUNC_LEXPR, builtin_patom, + "+", AO_LISP_FUNC_LEXPR, builtin_plus, + "-", AO_LISP_FUNC_LEXPR, builtin_minus, + "*", AO_LISP_FUNC_LEXPR, builtin_times, + "/", AO_LISP_FUNC_LEXPR, builtin_divide, + "%", AO_LISP_FUNC_LEXPR, builtin_mod, + "=", AO_LISP_FUNC_LEXPR, builtin_equal, + "<", AO_LISP_FUNC_LEXPR, builtin_less, + ">", AO_LISP_FUNC_LEXPR, builtin_greater, + "<=", AO_LISP_FUNC_LEXPR, builtin_less_equal, + ">=", AO_LISP_FUNC_LEXPR, builtin_greater_equal, }; -ao_poly -ao_lisp_set_cond(struct ao_lisp_cons *c) -{ - (void) c; - return AO_LISP_NIL; -} - #define N_FUNC (sizeof funcs / sizeof funcs[0]) /* Syntactic atoms */ @@ -90,19 +88,18 @@ int main(int argc, char **argv) { int f, o, i; - ao_poly atom, val; + ao_poly sexpr, val; struct ao_lisp_atom *a; struct ao_lisp_builtin *b; int in_atom; printf("/*\n"); printf(" * Generated file, do not edit\n"); - ao_lisp_root_add(&ao_lisp_frame_type, &globals); - globals = ao_lisp_frame_new(0); for (f = 0; f < N_FUNC; f++) { b = ao_lisp_make_builtin(funcs[f].func, funcs[f].args); a = ao_lisp_atom_intern(funcs[f].name); - globals = ao_lisp_frame_add(globals, ao_lisp_atom_poly(a), ao_lisp_builtin_poly(b)); + ao_lisp_atom_set(ao_lisp_atom_poly(a), + ao_lisp_builtin_poly(b)); } /* atoms for syntax */ @@ -110,23 +107,25 @@ main(int argc, char **argv) (void) ao_lisp_atom_intern(atoms[i]); /* boolean constants */ - a = ao_lisp_atom_intern("nil"); - globals = ao_lisp_frame_add(globals, ao_lisp_atom_poly(a), AO_LISP_NIL); + ao_lisp_atom_set(ao_lisp_atom_poly(ao_lisp_atom_intern("nil")), + AO_LISP_NIL); a = ao_lisp_atom_intern("t"); - globals = ao_lisp_frame_add(globals, ao_lisp_atom_poly(a), ao_lisp_atom_poly(a)); + ao_lisp_atom_set(ao_lisp_atom_poly(a), + ao_lisp_atom_poly(a)); for (;;) { - atom = ao_lisp_read(); - if (!atom) + sexpr = ao_lisp_read(); + if (!sexpr) break; - val = ao_lisp_read(); - if (!val) - break; - if (ao_lisp_poly_type(atom) != AO_LISP_ATOM) { - fprintf(stderr, "input must be atom val pairs\n"); + printf ("sexpr: "); + ao_lisp_poly_print(sexpr); + printf("\n"); + val = ao_lisp_eval(sexpr); + if (ao_lisp_exception) exit(1); - } - globals = ao_lisp_frame_add(globals, atom, val); + printf("\t"); + ao_lisp_poly_print(val); + printf("\n"); } /* Reduce to referenced values */ @@ -136,7 +135,7 @@ main(int argc, char **argv) printf("#define AO_LISP_POOL_CONST %d\n", ao_lisp_top); printf("extern const uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4)));\n"); printf("#define ao_builtin_atoms 0x%04x\n", ao_lisp_atom_poly(ao_lisp_atoms)); - printf("#define ao_builtin_frame 0x%04x\n", ao_lisp_frame_poly(globals)); + printf("#define ao_builtin_frame 0x%04x\n", ao_lisp_frame_poly(ao_lisp_frame_global)); for (a = ao_lisp_atoms; a; a = ao_lisp_poly_atom(a->next)) { char *n = a->name, c; diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index c11ec25d..476843d8 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -262,6 +262,7 @@ static const struct ao_lisp_type const *ao_lisp_types[AO_LISP_NUM_TYPE] = { [AO_LISP_ATOM] = &ao_lisp_atom_type, [AO_LISP_BUILTIN] = &ao_lisp_builtin_type, [AO_LISP_FRAME] = &ao_lisp_frame_type, + [AO_LISP_LAMBDA] = &ao_lisp_lambda_type, }; diff --git a/src/lisp/ao_lisp_prim.c b/src/lisp/ao_lisp_prim.c index 3c081ee8..bfd75ae3 100644 --- a/src/lisp/ao_lisp_prim.c +++ b/src/lisp/ao_lisp_prim.c @@ -45,7 +45,15 @@ static const struct ao_lisp_funcs ao_lisp_funcs[AO_LISP_NUM_TYPE] = { [AO_LISP_BUILTIN] = { .print = ao_lisp_builtin_print, .patom = ao_lisp_builtin_print, - } + }, + [AO_LISP_FRAME] = { + .print = ao_lisp_frame_print, + .patom = ao_lisp_frame_print, + }, + [AO_LISP_LAMBDA] = { + .print = ao_lisp_lambda_print, + .patom = ao_lisp_lambda_print, + }, }; static const struct ao_lisp_funcs * diff --git a/src/test/Makefile b/src/test/Makefile index 8d617eea..7395e832 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -94,7 +94,7 @@ ao_quaternion_test: ao_quaternion_test.c ao_quaternion.h AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o ao_lisp_cons.o ao_lisp_string.o \ ao_lisp_atom.o ao_lisp_int.o ao_lisp_prim.o ao_lisp_eval.o ao_lisp_poly.o \ ao_lisp_builtin.o ao_lisp_read.o ao_lisp_rep.o ao_lisp_frame.o \ - ao_lisp_error.o + ao_lisp_lambda.o ao_lisp_error.o ao_lisp_test: $(AO_LISP_OBJS) cc $(CFLAGS) -o $@ $(AO_LISP_OBJS) -- cgit v1.2.3 From 0ee44c8e4bf5dabe6a97bf76b366c8b767c387f8 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 9 Nov 2016 11:13:58 -0800 Subject: altos/lisp: macros appear to work now Needed an extra stack frame to stash the pre-macro state. This simplified macro processing quite a bit; a macro now just evaluates the function and then sends that result to be evaluated again. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 37 ++++++++++------- src/lisp/ao_lisp_atom.c | 2 +- src/lisp/ao_lisp_error.c | 5 +-- src/lisp/ao_lisp_eval.c | 105 +++++++++++++++++++++++++---------------------- 4 files changed, 81 insertions(+), 68 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 6a35d8ce..82ba5a20 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -78,6 +78,7 @@ extern uint16_t ao_lisp_top; #define AO_LISP_OOM 0x01 #define AO_LISP_DIVIDE_BY_ZERO 0x02 #define AO_LISP_INVALID 0x04 +#define AO_LISP_UNDEFINED 0x08 extern uint8_t ao_lisp_exception; @@ -156,28 +157,25 @@ ao_lisp_frame_poly(struct ao_lisp_frame *frame) { return ao_lisp_poly(frame, AO_LISP_OTHER); } -struct ao_lisp_stack { - ao_poly prev; - uint8_t state; - uint8_t macro; - ao_poly sexprs; - ao_poly values; - ao_poly values_tail; - ao_poly frame; - ao_poly macro_frame; - ao_poly list; -}; - enum eval_state { - eval_sexpr, + eval_sexpr, /* Evaluate an sexpr */ eval_val, eval_formal, eval_exec, - eval_lambda_done, eval_cond, eval_cond_test }; +struct ao_lisp_stack { + uint8_t state; /* enum eval_state */ + ao_poly prev; /* previous stack frame */ + ao_poly sexprs; /* expressions to evaluate */ + ao_poly values; /* values computed */ + ao_poly values_tail; /* end of the values list for easy appending */ + ao_poly frame; /* current lookup frame */ + ao_poly list; /* most recent function call */ +}; + static inline struct ao_lisp_stack * ao_lisp_poly_stack(ao_poly p) { @@ -559,6 +557,16 @@ int ao_lisp_stack_depth; #define DBG_POLY(a) ao_lisp_poly_print(a) #define OFFSET(a) ((a) ? (int) ((uint8_t *) a - ao_lisp_pool) : -1) #define DBG_STACK() ao_lisp_stack_print() +static inline void +ao_lisp_frames_dump(void) +{ + struct ao_lisp_stack *s; + DBGI(".. current frame: "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); + for (s = ao_lisp_stack; s; s = ao_lisp_poly_stack(s->prev)) { + DBGI(".. stack frame: "); DBG_POLY(s->frame); DBG("\n"); + } +} +#define DBG_FRAMES() ao_lisp_frames_dump() #else #define DBG_DO(a) #define DBG_INDENT() @@ -570,6 +578,7 @@ int ao_lisp_stack_depth; #define DBG_POLY(a) #define DBG_RESET() #define DBG_STACK() +#define DBG_FRAMES() #endif #endif /* _AO_LISP_H_ */ diff --git a/src/lisp/ao_lisp_atom.c b/src/lisp/ao_lisp_atom.c index d7cb1996..5c6d5a67 100644 --- a/src/lisp/ao_lisp_atom.c +++ b/src/lisp/ao_lisp_atom.c @@ -134,7 +134,7 @@ ao_lisp_atom_get(ao_poly atom) #endif if (ref) return *ref; - return AO_LISP_NIL; + return ao_lisp_error(AO_LISP_UNDEFINED, "undefined atom %s", ao_lisp_poly_atom(atom)->name); } ao_poly diff --git a/src/lisp/ao_lisp_error.c b/src/lisp/ao_lisp_error.c index cedc107c..8b9fe2d5 100644 --- a/src/lisp/ao_lisp_error.c +++ b/src/lisp/ao_lisp_error.c @@ -80,17 +80,16 @@ ao_lisp_stack_print(void) { struct ao_lisp_stack *s; printf("Value: "); ao_lisp_poly_print(ao_lisp_v); printf("\n"); - ao_lisp_error_frame(0, "Frame: ", ao_lisp_frame_current); printf("Stack:\n"); for (s = ao_lisp_stack; s; s = ao_lisp_poly_stack(s->prev)) { printf("\t[\n"); printf("\t\texpr: "); ao_lisp_poly_print(s->list); printf("\n"); printf("\t\tstate: %s\n", state_names[s->state]); - printf("\t\tmacro: %s\n", s->macro ? "true" : "false"); +// printf("\t\tmacro: %s\n", s->macro ? "true" : "false"); ao_lisp_error_cons ("sexprs: ", ao_lisp_poly_cons(s->sexprs)); ao_lisp_error_cons ("values: ", ao_lisp_poly_cons(s->values)); ao_lisp_error_frame(2, "frame: ", ao_lisp_poly_frame(s->frame)); - ao_lisp_error_frame(2, "mframe: ", ao_lisp_poly_frame(s->macro_frame)); +// ao_lisp_error_frame(2, "mframe: ", ao_lisp_poly_frame(s->macro_frame)); printf("\t]\n"); } } diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index f4196219..f3372f2a 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -12,7 +12,7 @@ * General Public License for more details. */ -#define DBG_EVAL 1 +#define DBG_EVAL 0 #include "ao_lisp.h" #include @@ -32,7 +32,6 @@ stack_mark(void *addr) ao_lisp_poly_mark(stack->values, 0); /* no need to mark values_tail */ ao_lisp_poly_mark(stack->frame, 0); - ao_lisp_poly_mark(stack->macro_frame, 0); stack = ao_lisp_poly_stack(stack->prev); if (ao_lisp_mark_memory(stack, sizeof (struct ao_lisp_stack))) break; @@ -53,7 +52,6 @@ stack_move(void *addr) (void) ao_lisp_poly_move(&stack->values, 0); (void) ao_lisp_poly_move(&stack->values_tail, 0); (void) ao_lisp_poly_move(&stack->frame, 0); - (void) ao_lisp_poly_move(&stack->macro_frame, 0); prev = ao_lisp_poly_stack(stack->prev); ret = ao_lisp_move(&ao_lisp_stack_type, &prev); if (prev != ao_lisp_poly_stack(stack->prev)) @@ -85,28 +83,15 @@ static void ao_lisp_stack_reset(struct ao_lisp_stack *stack) { stack->state = eval_sexpr; - stack->macro = 0; stack->sexprs = AO_LISP_NIL; stack->values = AO_LISP_NIL; stack->values_tail = AO_LISP_NIL; } -static void -ao_lisp_frames_dump(void) -{ - struct ao_lisp_stack *s; - DBGI(".. current frame: "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); - for (s = ao_lisp_stack; s; s = ao_lisp_poly_stack(s->prev)) { - DBGI(".. stack frame: "); DBG_POLY(s->frame); DBG("\n"); - DBGI(".. macro frame: "); DBG_POLY(s->frame); DBG("\n"); - } -} static int ao_lisp_stack_push(void) { - DBGI("stack push\n"); - DBG_IN(); struct ao_lisp_stack *stack = ao_lisp_alloc(sizeof (struct ao_lisp_stack)); if (!stack) return 0; @@ -115,7 +100,9 @@ ao_lisp_stack_push(void) stack->list = AO_LISP_NIL; ao_lisp_stack = stack; ao_lisp_stack_reset(stack); - ao_lisp_frames_dump(); + DBGI("stack push\n"); + DBG_IN(); + DBG_FRAMES(); return 1; } @@ -124,11 +111,14 @@ ao_lisp_stack_pop(void) { if (!ao_lisp_stack) return; - ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->frame); ao_lisp_stack = ao_lisp_poly_stack(ao_lisp_stack->prev); + if (ao_lisp_stack) + ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->frame); + else + ao_lisp_frame_current = NULL; DBG_OUT(); DBGI("stack pop\n"); - ao_lisp_frames_dump(); + DBG_FRAMES(); } static void @@ -246,19 +236,20 @@ static int ao_lisp_eval_val(void) { DBGI("val: "); DBG_POLY(ao_lisp_v); DBG("\n"); +#if 0 if (ao_lisp_stack->macro) { - DBGI("..macro %d\n", ao_lisp_stack->macro); - DBGI("..current frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); - DBGI("..saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n"); - DBGI("..macro frame "); DBG_POLY(ao_lisp_stack->macro_frame); DBG("\n"); - DBGI("..sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); - DBGI("..values "); DBG_POLY(ao_lisp_stack->values); DBG("\n"); + DBGI(".. end macro %d\n", ao_lisp_stack->macro); + DBGI(".. sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); + DBGI(".. values "); DBG_POLY(ao_lisp_stack->values); DBG("\n"); + ao_lisp_frames_dump(); + + ao_lisp_stack_pop(); +#if 0 /* * Re-use the current stack to evaluate * the value from the macro */ ao_lisp_stack->state = eval_sexpr; -// assert(ao_lisp_stack->frame == ao_lisp_stack->macro_frame); ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->macro_frame); ao_lisp_stack->frame = ao_lisp_stack->macro_frame; ao_lisp_stack->macro = 0; @@ -266,7 +257,10 @@ ao_lisp_eval_val(void) ao_lisp_stack->sexprs = AO_LISP_NIL; ao_lisp_stack->values = AO_LISP_NIL; ao_lisp_stack->values_tail = AO_LISP_NIL; - } else { +#endif + } else +#endif + { /* * Value computed, pop the stack * to figure out what to do with the value @@ -280,22 +274,25 @@ ao_lisp_eval_val(void) /* * A formal has been computed. * - * If this is the first formal, then - * check to see if we've got a lamda/lexpr or - * macro/nlambda. + * If this is the first formal, then check to see if we've got a + * lamda/lexpr or macro/nlambda. + * + * For lambda/lexpr, go compute another formal. This will terminate + * when the sexpr state sees nil. * - * For lambda/lexpr, go compute another formal. - * This will terminate when the sexpr state - * sees nil. + * For macro/nlambda, we're done, so move the sexprs into the values + * and go execute it. * - * For macro/nlambda, we're done, so move the - * sexprs into the values and go execute it. + * Macros have an additional step of saving a stack frame holding the + * macro value execution context, which then gets the result of the + * macro to run */ static int ao_lisp_eval_formal(void) { - ao_poly formal; + ao_poly formal; + struct ao_lisp_stack *prev; DBGI("formal: "); DBG_POLY(ao_lisp_v); DBG("\n"); @@ -307,17 +304,34 @@ ao_lisp_eval_formal(void) DBGI(".. lambda or lexpr\n"); break; case AO_LISP_FUNC_MACRO: - ao_lisp_stack->macro = 1; - DBGI(".. macro %d\n", ao_lisp_stack->macro); - DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); - DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n"); - ao_lisp_stack->macro_frame = ao_lisp_stack->frame; + /* Evaluate the result once more */ + prev = ao_lisp_stack; + ao_lisp_stack->state = eval_sexpr; + if (!ao_lisp_stack_push()) + return 0; + + /* After the function returns, take that + * value and re-evaluate it + */ + ao_lisp_stack->state = eval_sexpr; + ao_lisp_stack->sexprs = prev->sexprs; + prev->sexprs = AO_LISP_NIL; + + DBGI(".. start macro\n"); + DBGI(".. sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); + DBGI(".. values "); DBG_POLY(ao_lisp_stack->values); DBG("\n"); + DBG_FRAMES(); + /* fall through ... */ case AO_LISP_FUNC_NLAMBDA: DBGI(".. nlambda or macro\n"); + + /* use the raw sexprs as values */ ao_lisp_stack->values = ao_lisp_stack->sexprs; ao_lisp_stack->values_tail = AO_LISP_NIL; ao_lisp_stack->state = eval_exec; + + /* ready to execute now */ return 1; case -1: return 0; @@ -397,14 +411,6 @@ ao_lisp_eval_exec(void) return 1; } -static int -ao_lisp_eval_lambda_done(void) -{ - DBGI("lambda_done: "); DBG_POLY(ao_lisp_v); DBG("\n"); - DBG_STACK(); - return 1; -} - /* * Start evaluating the next cond clause * @@ -497,7 +503,6 @@ ao_lisp_eval(ao_poly _v) return AO_LISP_NIL; while (ao_lisp_stack) { -// DBG_STACK(); if (!(*evals[ao_lisp_stack->state])() || ao_lisp_exception) { ao_lisp_stack_clear(); return AO_LISP_NIL; -- cgit v1.2.3 From 417161dbb36323b5a6572859dedad02ca92fc65c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 9 Nov 2016 16:22:43 -0800 Subject: altos/lisp: Clean up OS integration bits, add defun Provide an abstraction for the OS interface so that it can build more cleanly on Linux and AltOS. Add defun macro. Signed-off-by: Keith Packard --- src/lambdakey-v1.0/Makefile | 1 + src/lambdakey-v1.0/ao_lisp_os.h | 56 ++++++++++++ src/lambdakey-v1.0/ao_pins.h | 2 +- src/lisp/Makefile | 3 +- src/lisp/ao_lisp.h | 19 ++-- src/lisp/ao_lisp_builtin.c | 36 +++++++- src/lisp/ao_lisp_const.lisp | 35 +++++++- src/lisp/ao_lisp_lambda.c | 188 ++++++++++++++++++++++++++++++++++++++++ src/lisp/ao_lisp_make_const.c | 16 +--- src/lisp/ao_lisp_mem.c | 8 +- src/lisp/ao_lisp_os.h | 51 +++++++++++ src/lisp/ao_lisp_poly.c | 85 +++++++++++++----- src/lisp/ao_lisp_prim.c | 86 ------------------ src/lisp/ao_lisp_read.c | 14 +-- src/test/Makefile | 5 +- 15 files changed, 442 insertions(+), 163 deletions(-) create mode 100644 src/lambdakey-v1.0/ao_lisp_os.h create mode 100644 src/lisp/ao_lisp_lambda.c create mode 100644 src/lisp/ao_lisp_os.h delete mode 100644 src/lisp/ao_lisp_prim.c (limited to 'src') diff --git a/src/lambdakey-v1.0/Makefile b/src/lambdakey-v1.0/Makefile index 4db0e290..ef03527e 100644 --- a/src/lambdakey-v1.0/Makefile +++ b/src/lambdakey-v1.0/Makefile @@ -47,6 +47,7 @@ ALTOS_SRC = \ ao_lisp_rep.c \ ao_lisp_frame.c \ ao_lisp_error.c \ + ao_lisp_lambda.c \ ao_exti_stm.c PRODUCT=LambdaKey-v1.0 diff --git a/src/lambdakey-v1.0/ao_lisp_os.h b/src/lambdakey-v1.0/ao_lisp_os.h new file mode 100644 index 00000000..df158f6a --- /dev/null +++ b/src/lambdakey-v1.0/ao_lisp_os.h @@ -0,0 +1,56 @@ +/* + * Copyright © 2016 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_LISP_OS_H_ +#define _AO_LISP_OS_H_ + +#include "ao.h" + +static inline int +ao_lisp_getc() { + static uint8_t at_eol; + int c; + + if (at_eol) { + ao_cmd_readline(); + at_eol = 0; + } + c = ao_cmd_lex(); + if (c == '\n') + at_eol = 1; + return c; +} + +static inline void +ao_lisp_abort(void) +{ + ao_panic(1); +} + +static inline void +ao_lisp_os_led(int led) +{ + ao_led_set(led); +} + +static inline void +ao_lisp_os_delay(int delay) +{ + ao_delay(AO_MS_TO_TICKS(delay)); +} + +#endif diff --git a/src/lambdakey-v1.0/ao_pins.h b/src/lambdakey-v1.0/ao_pins.h index 5a840f13..b8429c55 100644 --- a/src/lambdakey-v1.0/ao_pins.h +++ b/src/lambdakey-v1.0/ao_pins.h @@ -25,7 +25,7 @@ #define AO_LED_RED (1 << LED_PIN_RED) #define AO_LED_PANIC AO_LED_RED #define AO_CMD_LEN 128 -#define AO_LISP_POOL 2560 +#define AO_LISP_POOL 3072 #define AO_STACK_SIZE 1024 #define LEDS_AVAILABLE (AO_LED_RED) diff --git a/src/lisp/Makefile b/src/lisp/Makefile index f7edbe41..9c99f05c 100644 --- a/src/lisp/Makefile +++ b/src/lisp/Makefile @@ -14,7 +14,6 @@ SRCS=\ ao_lisp_atom.c \ ao_lisp_int.c \ ao_lisp_poly.c \ - ao_lisp_prim.c \ ao_lisp_builtin.c \ ao_lisp_read.c \ ao_lisp_frame.c \ @@ -24,7 +23,7 @@ SRCS=\ OBJS=$(SRCS:.c=.o) -CFLAGS=-DAO_LISP_MAKE_CONST -O0 -g +CFLAGS=-DAO_LISP_MAKE_CONST -O0 -g -I. HDRS=\ ao_lisp.h \ diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 82ba5a20..de55b307 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -15,17 +15,10 @@ #ifndef _AO_LISP_H_ #define _AO_LISP_H_ -#include - -#if !defined(AO_LISP_TEST) && !defined(AO_LISP_MAKE_CONST) -#include -#define AO_LISP_ALTOS 1 -#define abort() ao_panic(1) -#endif - #include #include -#include +//#include +#include #ifdef AO_LISP_MAKE_CONST #define AO_LISP_POOL_CONST 16384 @@ -45,6 +38,8 @@ extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST]; #define _ao_lisp_atom_last _atom("last") #define _ao_lisp_atom_cond _atom("cond") #define _ao_lisp_atom_lambda _atom("lambda") +#define _ao_lisp_atom_led _atom("led") +#define _ao_lisp_atom_delay _atom("delay") #else #include "ao_lisp_const.h" #ifndef AO_LISP_POOL @@ -99,7 +94,7 @@ ao_lisp_is_const(ao_poly poly) { static inline void * ao_lisp_ref(ao_poly poly) { if (poly == 0xBEEF) - abort(); + ao_lisp_abort(); if (poly == AO_LISP_NIL) return NULL; if (poly & AO_LISP_CONST) @@ -227,12 +222,14 @@ enum ao_lisp_builtin_id { builtin_greater, builtin_less_equal, builtin_greater_equal, + builtin_delay, + builtin_led, _builtin_last }; typedef ao_poly (*ao_lisp_func_t)(struct ao_lisp_cons *cons); -extern ao_lisp_func_t ao_lisp_builtins[]; +extern const ao_lisp_func_t ao_lisp_builtins[]; static inline ao_lisp_func_t ao_lisp_func(struct ao_lisp_builtin *b) diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index c38ba165..5bd180e2 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -72,11 +72,13 @@ static const ao_poly builtin_names[] = { [builtin_greater] = _ao_lisp_atom_3e, [builtin_less_equal] = _ao_lisp_atom_3c3d, [builtin_greater_equal] = _ao_lisp_atom_3e3d, + [builtin_delay] = _ao_lisp_atom_delay, + [builtin_led] = _ao_lisp_atom_led, }; static char * ao_lisp_builtin_name(enum ao_lisp_builtin_id b) { - if (0 <= b && b < _builtin_last) + if (b < _builtin_last) return ao_lisp_poly_atom(builtin_names[b])->name; return "???"; } @@ -448,7 +450,33 @@ ao_lisp_greater_equal(struct ao_lisp_cons *cons) return ao_lisp_compare(cons, builtin_greater_equal); } -ao_lisp_func_t ao_lisp_builtins[] = { +ao_poly +ao_lisp_led(struct ao_lisp_cons *cons) +{ + ao_poly led; + if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1)) + return AO_LISP_NIL; + if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_INT, 0)) + return AO_LISP_NIL; + led = ao_lisp_arg(cons, 0); + ao_lisp_os_led(ao_lisp_poly_int(led)); + return led; +} + +ao_poly +ao_lisp_delay(struct ao_lisp_cons *cons) +{ + ao_poly delay; + if (!ao_lisp_check_argc(_ao_lisp_atom_led, cons, 1, 1)) + return AO_LISP_NIL; + if (!ao_lisp_check_argt(_ao_lisp_atom_led, cons, 0, AO_LISP_INT, 0)) + return AO_LISP_NIL; + delay = ao_lisp_arg(cons, 0); + ao_lisp_os_delay(ao_lisp_poly_int(delay)); + return delay; +} + +const ao_lisp_func_t ao_lisp_builtins[] = { [builtin_lambda] = ao_lisp_lambda, [builtin_lexpr] = ao_lisp_lexpr, [builtin_nlambda] = ao_lisp_nlambda, @@ -472,6 +500,8 @@ ao_lisp_func_t ao_lisp_builtins[] = { [builtin_less] = ao_lisp_less, [builtin_greater] = ao_lisp_greater, [builtin_less_equal] = ao_lisp_less_equal, - [builtin_greater_equal] = ao_lisp_greater_equal + [builtin_greater_equal] = ao_lisp_greater_equal, + [builtin_led] = ao_lisp_led, + [builtin_delay] = ao_lisp_delay, }; diff --git a/src/lisp/ao_lisp_const.lisp b/src/lisp/ao_lisp_const.lisp index 621fefc4..08a511d9 100644 --- a/src/lisp/ao_lisp_const.lisp +++ b/src/lisp/ao_lisp_const.lisp @@ -14,9 +14,13 @@ (setq 1+ (lambda (x) (+ x 1))) (setq 1- (lambda (x) (- x 1))) - ; define a variable without returning the value + ; + ; Define a variable without returning the value + ; Useful when defining functions to avoid + ; having lots of output generated + ; -(set 'def (macro (def-param) +(setq def (macro (def-param) (list 'progn (list @@ -127,3 +131,30 @@ ) ) ) + + ; + ; A slightly more convenient form + ; for defining lambdas. + ; + ; (defun () s-exprs) + ; + +(def defun (macro (defun-param) + (let ((name (car defun-param)) + (args (cadr defun-param)) + (exprs (cdr (cdr defun-param)))) + (list + def + name + (list + 'lambda + args + (cond ((cdr exprs) + (cons progn exprs)) + ((car exprs)) + ) + ) + ) + ) + ) + ) diff --git a/src/lisp/ao_lisp_lambda.c b/src/lisp/ao_lisp_lambda.c new file mode 100644 index 00000000..cc5af4bc --- /dev/null +++ b/src/lisp/ao_lisp_lambda.c @@ -0,0 +1,188 @@ +/* + * Copyright © 2016 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#define DBG_EVAL 0 +#include "ao_lisp.h" + +int +lambda_size(void *addr) +{ + (void) addr; + return sizeof (struct ao_lisp_lambda); +} + +void +lambda_mark(void *addr) +{ + struct ao_lisp_lambda *lambda = addr; + + ao_lisp_poly_mark(lambda->code, 0); + ao_lisp_poly_mark(lambda->frame, 0); +} + +void +lambda_move(void *addr) +{ + struct ao_lisp_lambda *lambda = addr; + + ao_lisp_poly_move(&lambda->code, 0); + ao_lisp_poly_move(&lambda->frame, 0); +} + +const struct ao_lisp_type ao_lisp_lambda_type = { + .size = lambda_size, + .mark = lambda_mark, + .move = lambda_move, +}; + +static int +ao_lisp_cons_length(struct ao_lisp_cons *cons) +{ + int len = 0; + while (cons) { + len++; + cons = ao_lisp_poly_cons(cons->cdr); + } + return len; +} + +void +ao_lisp_lambda_print(ao_poly poly) +{ + struct ao_lisp_lambda *lambda = ao_lisp_poly_lambda(poly); + struct ao_lisp_cons *cons = ao_lisp_poly_cons(lambda->code); + + printf("("); + printf("%s", ao_lisp_args_name(lambda->args)); + while (cons) { + printf(" "); + ao_lisp_poly_print(cons->car); + cons = ao_lisp_poly_cons(cons->cdr); + } + printf(")"); +} + +ao_poly +ao_lisp_lambda_alloc(struct ao_lisp_cons *code, int args) +{ + struct ao_lisp_lambda *lambda = ao_lisp_alloc(sizeof (struct ao_lisp_lambda)); + struct ao_lisp_cons *arg; + int f; + + if (!lambda) + return AO_LISP_NIL; + + if (!ao_lisp_check_argc(_ao_lisp_atom_lambda, code, 2, 2)) + return AO_LISP_NIL; + if (!ao_lisp_check_argt(_ao_lisp_atom_lambda, code, 0, AO_LISP_CONS, 1)) + return AO_LISP_NIL; + f = 0; + arg = ao_lisp_poly_cons(ao_lisp_arg(code, 0)); + while (arg) { + if (ao_lisp_poly_type(arg->car) != AO_LISP_ATOM) + return ao_lisp_error(AO_LISP_INVALID, "formal %d is not an atom", f); + arg = ao_lisp_poly_cons(arg->cdr); + f++; + } + + lambda->type = AO_LISP_LAMBDA; + lambda->args = args; + lambda->code = ao_lisp_cons_poly(code); + lambda->frame = ao_lisp_frame_poly(ao_lisp_frame_current); + DBGI("build frame: "); DBG_POLY(lambda->frame); DBG("\n"); + DBG_STACK(); + return ao_lisp_lambda_poly(lambda); +} + +ao_poly +ao_lisp_lambda(struct ao_lisp_cons *cons) +{ + return ao_lisp_lambda_alloc(cons, AO_LISP_FUNC_LAMBDA); +} + +ao_poly +ao_lisp_lexpr(struct ao_lisp_cons *cons) +{ + return ao_lisp_lambda_alloc(cons, AO_LISP_FUNC_LEXPR); +} + +ao_poly +ao_lisp_nlambda(struct ao_lisp_cons *cons) +{ + return ao_lisp_lambda_alloc(cons, AO_LISP_FUNC_NLAMBDA); +} + +ao_poly +ao_lisp_macro(struct ao_lisp_cons *cons) +{ + return ao_lisp_lambda_alloc(cons, AO_LISP_FUNC_MACRO); +} + +ao_poly +ao_lisp_lambda_eval(struct ao_lisp_lambda *lambda, + struct ao_lisp_cons *cons) +{ + struct ao_lisp_cons *code; + struct ao_lisp_cons *args; + struct ao_lisp_frame *next_frame; + int args_wanted; + int args_provided; + + code = ao_lisp_poly_cons(lambda->code); + DBGI("lambda "); DBG_POLY(ao_lisp_lambda_poly(lambda)); DBG("\n"); + args = ao_lisp_poly_cons(ao_lisp_arg(code, 0)); + + args_wanted = ao_lisp_cons_length(args); + + /* Create a frame to hold the variables + */ + if (lambda->args == AO_LISP_FUNC_LAMBDA) + args_provided = ao_lisp_cons_length(cons) - 1; + else + args_provided = 1; + if (args_wanted != args_provided) + return ao_lisp_error(AO_LISP_INVALID, "need %d args, not %d", args_wanted, args_provided); + next_frame = ao_lisp_frame_new(args_wanted); + switch (lambda->args) { + case AO_LISP_FUNC_LAMBDA: { + int f; + struct ao_lisp_cons *vals = ao_lisp_poly_cons(cons->cdr); + + for (f = 0; f < args_wanted; f++) { + DBGI("bind "); DBG_POLY(args->car); DBG(" = "); DBG_POLY(vals->car); DBG("\n"); + next_frame->vals[f].atom = args->car; + next_frame->vals[f].val = vals->car; + args = ao_lisp_poly_cons(args->cdr); + vals = ao_lisp_poly_cons(vals->cdr); + } + break; + } + case AO_LISP_FUNC_LEXPR: + case AO_LISP_FUNC_NLAMBDA: + case AO_LISP_FUNC_MACRO: + DBGI("bind "); DBG_POLY(args->car); DBG(" = "); DBG_POLY(cons->cdr); DBG("\n"); + next_frame->vals[0].atom = args->car; + next_frame->vals[0].val = cons->cdr; + break; + } + next_frame->next = lambda->frame; + DBGI("eval frame: "); DBG_POLY(ao_lisp_frame_poly(next_frame)); DBG("\n"); + ao_lisp_frame_current = next_frame; + ao_lisp_stack->frame = ao_lisp_frame_poly(ao_lisp_frame_current); + DBG_STACK(); + return ao_lisp_arg(code, 1); +} diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index 501052b9..6f852f9d 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -57,20 +57,12 @@ struct builtin_func funcs[] = { ">", AO_LISP_FUNC_LEXPR, builtin_greater, "<=", AO_LISP_FUNC_LEXPR, builtin_less_equal, ">=", AO_LISP_FUNC_LEXPR, builtin_greater_equal, + "delay", AO_LISP_FUNC_LAMBDA, builtin_delay, + "led", AO_LISP_FUNC_LEXPR, builtin_led, }; #define N_FUNC (sizeof funcs / sizeof funcs[0]) -/* Syntactic atoms */ -char *atoms[] = { - "lambda", - "nlambda", - "lexpr", - "macro" -}; - -#define N_ATOM (sizeof atoms / sizeof atoms[0]) - struct ao_lisp_frame *globals; static int @@ -102,10 +94,6 @@ main(int argc, char **argv) ao_lisp_builtin_poly(b)); } - /* atoms for syntax */ - for (i = 0; i < N_ATOM; i++) - (void) ao_lisp_atom_intern(atoms[i]); - /* boolean constants */ ao_lisp_atom_set(ao_lisp_atom_poly(ao_lisp_atom_intern("nil")), AO_LISP_NIL); diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 476843d8..66e09db0 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -331,7 +331,7 @@ ao_lisp_collect(void) move_object(); DBG("\tbusy size %d\n", move_size); if (move_size == 0) - abort(); + ao_lisp_abort(); clear_object(ao_lisp_busy, move_old, move_size); mark_object(ao_lisp_busy, move_new, move_size); if (busy_object(ao_lisp_cons, move_old)) { @@ -431,7 +431,7 @@ ao_lisp_move(const struct ao_lisp_type *type, void **ref) #endif DBG_MOVE("object %d\n", DBG_OFFSET(addr)); if (!AO_LISP_IS_POOL(a)) - abort(); + ao_lisp_abort(); DBG_MOVE_IN(); addr = check_move(addr, size); if (addr != *ref) @@ -495,7 +495,7 @@ ao_lisp_poly_move(ao_poly *ref, uint8_t do_note_cons) type = ao_lisp_other_type(ao_lisp_move_map(ao_lisp_poly_other(p))); if (type >= AO_LISP_NUM_TYPE) - abort(); + ao_lisp_abort(); lisp_type = ao_lisp_types[type]; if (!lisp_type) @@ -601,7 +601,7 @@ ao_lisp_root_add(const struct ao_lisp_type *type, void *addr) return 1; } } - abort(); + ao_lisp_abort(); return 0; } diff --git a/src/lisp/ao_lisp_os.h b/src/lisp/ao_lisp_os.h new file mode 100644 index 00000000..55ffed50 --- /dev/null +++ b/src/lisp/ao_lisp_os.h @@ -0,0 +1,51 @@ +/* + * Copyright © 2016 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_LISP_OS_H_ +#define _AO_LISP_OS_H_ + +#include +#include +#include + +static inline int +ao_lisp_getc() { + return getchar(); +} + +static inline void +ao_lisp_abort(void) +{ + abort(); +} + +static inline void +ao_lisp_os_led(int led) +{ + printf("leds set to 0x%x\n", led); +} + +static inline void +ao_lisp_os_delay(int delay) +{ + struct timespec ts = { + .tv_sec = delay / 1000, + .tv_nsec = (delay % 1000) * 1000000, + }; + nanosleep(&ts, NULL); +} +#endif diff --git a/src/lisp/ao_lisp_poly.c b/src/lisp/ao_lisp_poly.c index c6ca0a97..bfd75ae3 100644 --- a/src/lisp/ao_lisp_poly.c +++ b/src/lisp/ao_lisp_poly.c @@ -14,34 +14,73 @@ #include "ao_lisp.h" -/* +#if 0 +#define DBG(...) printf (__VA_ARGS__) +#else +#define DBG(...) +#endif -static const struct ao_lisp_builtin builtin_plus = { - .type = AO_LISP_BUILTIN, - .func = ao_lisp_plus, - .name = "+" +struct ao_lisp_funcs { + void (*print)(ao_poly); + void (*patom)(ao_poly); }; -static const struct ao_lisp_atom atom_plus = { - .type = AO_LISP_ATOM, - .val = AO_LISP_OTHER_POLY(&builtin_plus), - .next = AO_LISP_ATOM_CONST, - .name = "plus" +static const struct ao_lisp_funcs ao_lisp_funcs[AO_LISP_NUM_TYPE] = { + [AO_LISP_CONS] = { + .print = ao_lisp_cons_print, + .patom = ao_lisp_cons_patom, + }, + [AO_LISP_STRING] = { + .print = ao_lisp_string_print, + .patom = ao_lisp_string_patom, + }, + [AO_LISP_INT] = { + .print = ao_lisp_int_print, + .patom = ao_lisp_int_print, + }, + [AO_LISP_ATOM] = { + .print = ao_lisp_atom_print, + .patom = ao_lisp_atom_print, + }, + [AO_LISP_BUILTIN] = { + .print = ao_lisp_builtin_print, + .patom = ao_lisp_builtin_print, + }, + [AO_LISP_FRAME] = { + .print = ao_lisp_frame_print, + .patom = ao_lisp_frame_print, + }, + [AO_LISP_LAMBDA] = { + .print = ao_lisp_lambda_print, + .patom = ao_lisp_lambda_print, + }, }; -static const struct ao_lisp_builtin builtin_minus = { - .type = AO_LISP_BUILTIN, - .func = ao_lisp_minus -}; +static const struct ao_lisp_funcs * +funcs(ao_poly p) +{ + uint8_t type = ao_lisp_poly_type(p); -static const struct ao_lisp_builtin builtin_times = { - .type = AO_LISP_BUILTIN, - .func = ao_lisp_times -}; + if (type < AO_LISP_NUM_TYPE) + return &ao_lisp_funcs[type]; + return NULL; +} +void +ao_lisp_poly_print(ao_poly p) +{ + const struct ao_lisp_funcs *f = funcs(p); + + if (f && f->print) + f->print(p); +} + +void +ao_lisp_poly_patom(ao_poly p) +{ + const struct ao_lisp_funcs *f = funcs(p); + + if (f && f->patom) + f->patom(p); +} -const struct ao_lisp_atom const *ao_lisp_builtins[] = { - &atom_plus, - 0 -}; -*/ diff --git a/src/lisp/ao_lisp_prim.c b/src/lisp/ao_lisp_prim.c deleted file mode 100644 index bfd75ae3..00000000 --- a/src/lisp/ao_lisp_prim.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright © 2016 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 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include "ao_lisp.h" - -#if 0 -#define DBG(...) printf (__VA_ARGS__) -#else -#define DBG(...) -#endif - -struct ao_lisp_funcs { - void (*print)(ao_poly); - void (*patom)(ao_poly); -}; - -static const struct ao_lisp_funcs ao_lisp_funcs[AO_LISP_NUM_TYPE] = { - [AO_LISP_CONS] = { - .print = ao_lisp_cons_print, - .patom = ao_lisp_cons_patom, - }, - [AO_LISP_STRING] = { - .print = ao_lisp_string_print, - .patom = ao_lisp_string_patom, - }, - [AO_LISP_INT] = { - .print = ao_lisp_int_print, - .patom = ao_lisp_int_print, - }, - [AO_LISP_ATOM] = { - .print = ao_lisp_atom_print, - .patom = ao_lisp_atom_print, - }, - [AO_LISP_BUILTIN] = { - .print = ao_lisp_builtin_print, - .patom = ao_lisp_builtin_print, - }, - [AO_LISP_FRAME] = { - .print = ao_lisp_frame_print, - .patom = ao_lisp_frame_print, - }, - [AO_LISP_LAMBDA] = { - .print = ao_lisp_lambda_print, - .patom = ao_lisp_lambda_print, - }, -}; - -static const struct ao_lisp_funcs * -funcs(ao_poly p) -{ - uint8_t type = ao_lisp_poly_type(p); - - if (type < AO_LISP_NUM_TYPE) - return &ao_lisp_funcs[type]; - return NULL; -} - -void -ao_lisp_poly_print(ao_poly p) -{ - const struct ao_lisp_funcs *f = funcs(p); - - if (f && f->print) - f->print(p); -} - -void -ao_lisp_poly_patom(ao_poly p) -{ - const struct ao_lisp_funcs *f = funcs(p); - - if (f && f->patom) - f->patom(p); -} - diff --git a/src/lisp/ao_lisp_read.c b/src/lisp/ao_lisp_read.c index bc1eb36b..3a2ef7f1 100644 --- a/src/lisp/ao_lisp_read.c +++ b/src/lisp/ao_lisp_read.c @@ -156,19 +156,7 @@ lex_get() c = lex_unget_c; lex_unget_c = 0; } else { -#if AO_LISP_ALTOS - static uint8_t at_eol; - - if (at_eol) { - ao_cmd_readline(); - at_eol = 0; - } - c = ao_cmd_lex(); - if (c == '\n') - at_eol = 1; -#else - c = getchar(); -#endif + c = ao_lisp_getc(); } return c; } diff --git a/src/test/Makefile b/src/test/Makefile index 7395e832..d6777090 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -88,11 +88,8 @@ ao_ms5607_convert_test: ao_ms5607_convert_test.c ao_ms5607_convert_8051.c ao_int ao_quaternion_test: ao_quaternion_test.c ao_quaternion.h cc $(CFLAGS) -o $@ ao_quaternion_test.c -lm - -#AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o ao_lisp_lex.o ao_lisp_cons.o ao_lisp_string.o ao_lisp_atom.o ao_lisp_int.o ao_lisp_prim.o ao_lisp_eval.o ao_lisp_poly.o ao_lisp_builtin.o ao_lisp_read.o - AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o ao_lisp_cons.o ao_lisp_string.o \ - ao_lisp_atom.o ao_lisp_int.o ao_lisp_prim.o ao_lisp_eval.o ao_lisp_poly.o \ + ao_lisp_atom.o ao_lisp_int.o ao_lisp_eval.o ao_lisp_poly.o \ ao_lisp_builtin.o ao_lisp_read.o ao_lisp_rep.o ao_lisp_frame.o \ ao_lisp_lambda.o ao_lisp_error.o -- cgit v1.2.3 From c7d7cdc2318a97534c4c1f9c6fd2b51644be729d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 10 Nov 2016 11:30:55 -0800 Subject: altos/lisp: add progn, while, read and eval Progn as a builtin will help with tail-recursion. while provides for loops until tail-recursion works :-) read and eval are kinda useful. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 11 +++++- src/lisp/ao_lisp_builtin.c | 41 +++++++++++++++++++++ src/lisp/ao_lisp_const.lisp | 2 +- src/lisp/ao_lisp_error.c | 1 + src/lisp/ao_lisp_eval.c | 84 ++++++++++++++++++++++++++++++++++++++++++- src/lisp/ao_lisp_make_const.c | 4 +++ 6 files changed, 140 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index de55b307..d265ea7b 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -40,6 +40,8 @@ extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST]; #define _ao_lisp_atom_lambda _atom("lambda") #define _ao_lisp_atom_led _atom("led") #define _ao_lisp_atom_delay _atom("delay") +#define _ao_lisp_atom_eval _atom("eval") +#define _ao_lisp_atom_read _atom("read") #else #include "ao_lisp_const.h" #ifndef AO_LISP_POOL @@ -158,7 +160,10 @@ enum eval_state { eval_formal, eval_exec, eval_cond, - eval_cond_test + eval_cond_test, + eval_progn, + eval_while, + eval_while_test, }; struct ao_lisp_stack { @@ -198,6 +203,8 @@ struct ao_lisp_builtin { }; enum ao_lisp_builtin_id { + builtin_eval, + builtin_read, builtin_lambda, builtin_lexpr, builtin_nlambda, @@ -210,6 +217,8 @@ enum ao_lisp_builtin_id { builtin_set, builtin_setq, builtin_cond, + builtin_progn, + builtin_while, builtin_print, builtin_patom, builtin_plus, diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index 5bd180e2..57d9ee10 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -48,6 +48,8 @@ char *ao_lisp_args_name(uint8_t args) { } #else static const ao_poly builtin_names[] = { + [builtin_eval] = _ao_lisp_atom_eval, + [builtin_read] = _ao_lisp_atom_read, [builtin_lambda] = _ao_lisp_atom_lambda, [builtin_lexpr] = _ao_lisp_atom_lexpr, [builtin_nlambda] = _ao_lisp_atom_nlambda, @@ -60,6 +62,8 @@ static const ao_poly builtin_names[] = { [builtin_set] = _ao_lisp_atom_set, [builtin_setq] = _ao_lisp_atom_setq, [builtin_cond] = _ao_lisp_atom_cond, + [builtin_progn] = _ao_lisp_atom_progn, + [builtin_while] = _ao_lisp_atom_while, [builtin_print] = _ao_lisp_atom_print, [builtin_patom] = _ao_lisp_atom_patom, [builtin_plus] = _ao_lisp_atom_2b, @@ -235,6 +239,22 @@ ao_lisp_cond(struct ao_lisp_cons *cons) return AO_LISP_NIL; } +ao_poly +ao_lisp_progn(struct ao_lisp_cons *cons) +{ + ao_lisp_stack->state = eval_progn; + ao_lisp_stack->sexprs = ao_lisp_cons_poly(cons); + return AO_LISP_NIL; +} + +ao_poly +ao_lisp_while(struct ao_lisp_cons *cons) +{ + ao_lisp_stack->state = eval_while; + ao_lisp_stack->sexprs = ao_lisp_cons_poly(cons); + return AO_LISP_NIL; +} + ao_poly ao_lisp_print(struct ao_lisp_cons *cons) { @@ -476,7 +496,26 @@ ao_lisp_delay(struct ao_lisp_cons *cons) return delay; } +ao_poly +ao_lisp_do_eval(struct ao_lisp_cons *cons) +{ + if (!ao_lisp_check_argc(_ao_lisp_atom_eval, cons, 1, 1)) + return AO_LISP_NIL; + ao_lisp_stack->state = eval_sexpr; + return cons->car; +} + +ao_poly +ao_lisp_do_read(struct ao_lisp_cons *cons) +{ + if (!ao_lisp_check_argc(_ao_lisp_atom_read, cons, 0, 0)) + return AO_LISP_NIL; + return ao_lisp_read(); +} + const ao_lisp_func_t ao_lisp_builtins[] = { + [builtin_eval] = ao_lisp_do_eval, + [builtin_read] = ao_lisp_do_read, [builtin_lambda] = ao_lisp_lambda, [builtin_lexpr] = ao_lisp_lexpr, [builtin_nlambda] = ao_lisp_nlambda, @@ -489,6 +528,8 @@ const ao_lisp_func_t ao_lisp_builtins[] = { [builtin_set] = ao_lisp_set, [builtin_setq] = ao_lisp_setq, [builtin_cond] = ao_lisp_cond, + [builtin_progn] = ao_lisp_progn, + [builtin_while] = ao_lisp_while, [builtin_print] = ao_lisp_print, [builtin_patom] = ao_lisp_patom, [builtin_plus] = ao_lisp_plus, diff --git a/src/lisp/ao_lisp_const.lisp b/src/lisp/ao_lisp_const.lisp index 08a511d9..c6f50e34 100644 --- a/src/lisp/ao_lisp_const.lisp +++ b/src/lisp/ao_lisp_const.lisp @@ -7,7 +7,7 @@ ; evaluate a list of sexprs -(setq progn (lexpr (l) (last l))) +;(setq progn (lexpr (l) (last l))) ; simple math operators diff --git a/src/lisp/ao_lisp_error.c b/src/lisp/ao_lisp_error.c index 8b9fe2d5..cfa78d22 100644 --- a/src/lisp/ao_lisp_error.c +++ b/src/lisp/ao_lisp_error.c @@ -73,6 +73,7 @@ static const char *state_names[] = { "exec", "cond", "cond_test", + "progn", }; void diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index f3372f2a..c5addcb0 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -12,7 +12,7 @@ * General Public License for more details. */ -#define DBG_EVAL 0 +#define DBG_EVAL 1 #include "ao_lisp.h" #include @@ -478,6 +478,85 @@ ao_lisp_eval_cond_test(void) return 1; } +/* + * Evaluate a list of sexprs, returning the value from the last one. + * + * ao_lisp_progn records the list in stack->sexprs, so we just need to + * walk that list. Set ao_lisp_v to the car of the list and jump to + * eval_sexpr. When that's done, it will land in eval_val. For all but + * the last, leave a stack frame with eval_progn set so that we come + * back here. For the last, don't add a stack frame so that we can + * just continue on. + */ +static int +ao_lisp_eval_progn(void) +{ + DBGI("progn: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); + DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); + DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n"); + + if (!ao_lisp_stack->sexprs) { + ao_lisp_v = AO_LISP_NIL; + ao_lisp_stack->state = eval_val; + } else { + ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car; + ao_lisp_stack->sexprs = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr; + if (ao_lisp_stack->sexprs) { + ao_lisp_stack->state = eval_progn; + if (!ao_lisp_stack_push()) + return 0; + } + ao_lisp_stack->state = eval_sexpr; + } + return 1; +} + +/* + * Conditionally execute a list of sexprs while the first is true + */ +static int +ao_lisp_eval_while(void) +{ + DBGI("while: "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); + DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); + DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n"); + + if (!ao_lisp_stack->sexprs) { + ao_lisp_v = AO_LISP_NIL; + ao_lisp_stack->state = eval_val; + } else { + ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car; + ao_lisp_stack->state = eval_while_test; + if (!ao_lisp_stack_push()) + return 0; + ao_lisp_stack->state = eval_sexpr; + } + return 1; +} + +/* + * Check the while condition, terminate the loop if nil. Otherwise keep going + */ +static int +ao_lisp_eval_while_test(void) +{ + DBGI("while_test: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); + DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); + DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n"); + + if (ao_lisp_v) { + ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr; + if (ao_lisp_v) + ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car; + ao_lisp_stack->state = eval_while; + if (!ao_lisp_stack_push()) + return 0; + } + else + ao_lisp_stack->state = eval_val; + return 1; +} + static int (*const evals[])(void) = { [eval_sexpr] = ao_lisp_eval_sexpr, [eval_val] = ao_lisp_eval_val, @@ -485,6 +564,9 @@ static int (*const evals[])(void) = { [eval_exec] = ao_lisp_eval_exec, [eval_cond] = ao_lisp_eval_cond, [eval_cond_test] = ao_lisp_eval_cond_test, + [eval_progn] = ao_lisp_eval_progn, + [eval_while] = ao_lisp_eval_while, + [eval_while_test] = ao_lisp_eval_while_test, }; ao_poly diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index 6f852f9d..bb4afbfb 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -33,6 +33,8 @@ struct builtin_func { }; struct builtin_func funcs[] = { + "eval", AO_LISP_FUNC_LAMBDA, builtin_eval, + "read", AO_LISP_FUNC_LAMBDA, builtin_read, "lambda", AO_LISP_FUNC_NLAMBDA, builtin_lambda, "lexpr", AO_LISP_FUNC_NLAMBDA, builtin_lexpr, "nlambda", AO_LISP_FUNC_NLAMBDA, builtin_nlambda, @@ -45,6 +47,8 @@ struct builtin_func funcs[] = { "set", AO_LISP_FUNC_LAMBDA, builtin_set, "setq", AO_LISP_FUNC_MACRO, builtin_setq, "cond", AO_LISP_FUNC_NLAMBDA, builtin_cond, + "progn", AO_LISP_FUNC_NLAMBDA, builtin_progn, + "while", AO_LISP_FUNC_NLAMBDA, builtin_while, "print", AO_LISP_FUNC_LEXPR, builtin_print, "patom", AO_LISP_FUNC_LEXPR, builtin_patom, "+", AO_LISP_FUNC_LEXPR, builtin_plus, -- cgit v1.2.3 From fb710f7f4f24f74ac3d45fcc423803384d986bb2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 10 Nov 2016 23:24:11 -0800 Subject: altos/lisp: use regular read-eval-print loop for make const No need to open code this sequence of operations. Signed-off-by: Keith Packard --- src/lisp/Makefile | 1 + src/lisp/ao_lisp_make_const.c | 20 ++++++-------------- 2 files changed, 7 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/lisp/Makefile b/src/lisp/Makefile index 9c99f05c..aa542021 100644 --- a/src/lisp/Makefile +++ b/src/lisp/Makefile @@ -19,6 +19,7 @@ SRCS=\ ao_lisp_frame.c \ ao_lisp_lambda.c \ ao_lisp_eval.c \ + ao_lisp_rep.c \ ao_lisp_error.c OBJS=$(SRCS:.c=.o) diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index bb4afbfb..4fc43e58 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -105,20 +105,12 @@ main(int argc, char **argv) ao_lisp_atom_set(ao_lisp_atom_poly(a), ao_lisp_atom_poly(a)); - for (;;) { - sexpr = ao_lisp_read(); - if (!sexpr) - break; - printf ("sexpr: "); - ao_lisp_poly_print(sexpr); - printf("\n"); - val = ao_lisp_eval(sexpr); - if (ao_lisp_exception) - exit(1); - printf("\t"); - ao_lisp_poly_print(val); - printf("\n"); - } + /* end of file value */ + a = ao_lisp_atom_intern("eof"); + ao_lisp_atom_set(ao_lisp_atom_poly(a), + ao_lisp_atom_poly(a)); + + ao_lisp_read_eval_print(); /* Reduce to referenced values */ ao_lisp_collect(); -- cgit v1.2.3 From 92cdc0cf0e80c1ff3f31cce20fc2b9bda86e3638 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 10 Nov 2016 23:25:56 -0800 Subject: altos/lisp: Make read() return eof atom on end of file Also make it an exception to hit eof in the middle of an sexpr. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 2 ++ src/lisp/ao_lisp_read.c | 18 ++++++++++++++---- src/lisp/ao_lisp_rep.c | 3 +-- 3 files changed, 17 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index d265ea7b..6122a2ed 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -42,6 +42,7 @@ extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST]; #define _ao_lisp_atom_delay _atom("delay") #define _ao_lisp_atom_eval _atom("eval") #define _ao_lisp_atom_read _atom("read") +#define _ao_lisp_atom_eof _atom("eof") #else #include "ao_lisp_const.h" #ifndef AO_LISP_POOL @@ -76,6 +77,7 @@ extern uint16_t ao_lisp_top; #define AO_LISP_DIVIDE_BY_ZERO 0x02 #define AO_LISP_INVALID 0x04 #define AO_LISP_UNDEFINED 0x08 +#define AO_LISP_EOF 0x10 extern uint8_t ao_lisp_exception; diff --git a/src/lisp/ao_lisp_read.c b/src/lisp/ao_lisp_read.c index 3a2ef7f1..7a5751ce 100644 --- a/src/lisp/ao_lisp_read.c +++ b/src/lisp/ao_lisp_read.c @@ -12,6 +12,7 @@ * General Public License for more details. */ +#define DBG_EVAL 0 #include "ao_lisp.h" #include "ao_lisp_read.h" @@ -270,7 +271,7 @@ lex(void) for (;;) { c = lexc(); if (lex_class & ENDOFFILE) - return AO_LISP_NIL; + return END; if (lex_class & WHITE) continue; @@ -278,7 +279,7 @@ lex(void) if (lex_class & COMMENT) { while ((c = lexc()) != '\n') { if (lex_class & ENDOFFILE) - return AO_LISP_NIL; + return END; } continue; } @@ -364,6 +365,8 @@ static struct ao_lisp_cons *read_stack; static int push_read_stack(int cons, int in_quote) { + DBGI("push read stack %p %d\n", read_cons, in_quote); + DBG_IN(); if (cons) { read_stack = ao_lisp_cons_cons(ao_lisp_cons_poly(read_cons), ao_lisp_cons_cons(ao_lisp_int_poly(in_quote), @@ -394,6 +397,8 @@ pop_read_stack(int cons) read_cons_tail = 0; read_stack = 0; } + DBG_OUT(); + DBGI("pop read stack %p %d\n", read_cons, in_quote); return in_quote; } @@ -413,6 +418,7 @@ ao_lisp_read(void) been_here = 1; } parse_token = lex(); + DBGI("token %d (%s)\n", parse_token, token_string); cons = 0; in_quote = 0; @@ -424,12 +430,15 @@ ao_lisp_read(void) cons++; in_quote = 0; parse_token = lex(); + DBGI("token %d (%s)\n", parse_token, token_string); } switch (parse_token) { - case ENDOFFILE: + case END: default: - v = AO_LISP_NIL; + if (cons) + ao_lisp_error(AO_LISP_EOF, "unexpected end of file"); + return _ao_lisp_atom_eof; break; case NAME: atom = ao_lisp_atom_intern(token_string); @@ -490,6 +499,7 @@ ao_lisp_read(void) } parse_token = lex(); + DBGI("token %d (%s)\n", parse_token, token_string); } return v; } diff --git a/src/lisp/ao_lisp_rep.c b/src/lisp/ao_lisp_rep.c index d780186a..ef7dbaf2 100644 --- a/src/lisp/ao_lisp_rep.c +++ b/src/lisp/ao_lisp_rep.c @@ -20,9 +20,8 @@ ao_lisp_read_eval_print(void) ao_poly in, out = AO_LISP_NIL; for(;;) { in = ao_lisp_read(); - if (!in) + if (in == _ao_lisp_atom_eof) break; -// printf ("in: "); ao_lisp_poly_print(in); printf("\n"); out = ao_lisp_eval(in); if (ao_lisp_exception) { ao_lisp_exception = 0; -- cgit v1.2.3 From 137898e3431d887e75b09d8c1ce57297a1558e43 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 10 Nov 2016 23:28:26 -0800 Subject: altos/lisp: Improve lisp test program UI Add a prompt for stdin, read from other files on command line before stdin. Signed-off-by: Keith Packard --- src/test/ao_lisp_os.h | 48 ++++++++++++++++++++++++++++++++++ src/test/ao_lisp_test.c | 68 +++++++++++++++++++------------------------------ 2 files changed, 74 insertions(+), 42 deletions(-) create mode 100644 src/test/ao_lisp_os.h (limited to 'src') diff --git a/src/test/ao_lisp_os.h b/src/test/ao_lisp_os.h new file mode 100644 index 00000000..19bd4f64 --- /dev/null +++ b/src/test/ao_lisp_os.h @@ -0,0 +1,48 @@ +/* + * Copyright © 2016 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_LISP_OS_H_ +#define _AO_LISP_OS_H_ + +#include +#include +#include + +extern int ao_lisp_getc(void); + +static inline void +ao_lisp_abort(void) +{ + abort(); +} + +static inline void +ao_lisp_os_led(int led) +{ + printf("leds set to 0x%x\n", led); +} + +static inline void +ao_lisp_os_delay(int delay) +{ + struct timespec ts = { + .tv_sec = delay / 1000, + .tv_nsec = (delay % 1000) * 1000000, + }; + nanosleep(&ts, NULL); +} +#endif diff --git a/src/test/ao_lisp_test.c b/src/test/ao_lisp_test.c index 8bc677da..69739100 100644 --- a/src/test/ao_lisp_test.c +++ b/src/test/ao_lisp_test.c @@ -15,55 +15,39 @@ #include "ao_lisp.h" #include -#if 0 -static struct ao_lisp_cons *list; -static char *string; -#endif +static FILE *ao_lisp_file; +static int newline = 1; int -main (int argc, char **argv) +ao_lisp_getc(void) { -#if 0 - int i, j; + int c; - struct ao_lisp_atom *atom; - ao_lisp_root_add(&ao_lisp_cons_type, (void **) &list); - ao_lisp_root_add(&ao_lisp_string_type, (void **) &string); + if (ao_lisp_file) + return getc(ao_lisp_file); - /* allocator test */ - for (j = 0; j < 10; j++) { - list = 0; - string = ao_lisp_string_new(0); - for (i = 0; i < 2; i++) { - string = ao_lisp_string_cat(string, "a"); - list = ao_lisp_cons_cons(ao_lisp_string_poly(string), list); - list = ao_lisp_cons_cons(ao_lisp_int_poly(i), list); - atom = ao_lisp_atom_intern("ant"); - list = ao_lisp_cons_cons(ao_lisp_atom_poly(atom), list); - } - ao_lisp_poly_print(ao_lisp_cons_poly(list)); - printf("\n"); + if (newline) { + printf("> "); + newline = 0; } + c = getchar(); + if (c == '\n') + newline = 1; + return c; +} - for (atom = ao_lisp_poly_atom(ao_builtin_atoms); atom; atom = ao_lisp_poly_atom(atom->next)) { - printf("%s = ", atom->name); - ao_lisp_poly_print(ao_lisp_atom_get(ao_lisp_atom_poly(atom))); - printf("\n"); +int +main (int argc, char **argv) +{ + while (*++argv) { + ao_lisp_file = fopen(*argv, "r"); + if (!ao_lisp_file) { + perror(*argv); + exit(1); + } + ao_lisp_read_eval_print(); + fclose(ao_lisp_file); + ao_lisp_file = NULL; } -#endif -#if 0 - list = ao_lisp_cons_cons(ao_lisp_atom_poly(ao_lisp_atom_intern("+")), - ao_lisp_cons_cons(ao_lisp_cons_poly(ao_lisp_cons_cons(ao_lisp_atom_poly(ao_lisp_atom_intern("+")), - ao_lisp_cons_cons(ao_lisp_int_poly(3), - ao_lisp_cons_cons(ao_lisp_int_poly(4), NULL)))), - ao_lisp_cons_cons(ao_lisp_int_poly(2), NULL))); - printf("list: "); - ao_lisp_poly_print(ao_lisp_cons_poly(list)); - printf ("\n"); - ao_lisp_poly_print(ao_lisp_eval(ao_lisp_cons_poly(list))); - printf ("\n"); -#endif -#if 1 ao_lisp_read_eval_print(); -#endif } -- cgit v1.2.3 From 7da6bfc195fad97e3afc576c609897c131fd4d8c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 10 Nov 2016 23:29:21 -0800 Subject: altos/lisp: Deal with memory compation in the middle of operations Handle memory compaction in places where we've got pointers into the heap across an allocation operation. Either re-compute the values from managed global references or add new roots across the allocation. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 7 +-- src/lisp/ao_lisp_atom.c | 2 +- src/lisp/ao_lisp_cons.c | 8 ++- src/lisp/ao_lisp_eval.c | 59 +++++------------- src/lisp/ao_lisp_frame.c | 28 ++++++--- src/lisp/ao_lisp_lambda.c | 19 ++++-- src/lisp/ao_lisp_mem.c | 149 ++++++++++++++++++++++++---------------------- 7 files changed, 137 insertions(+), 135 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 6122a2ed..60a97f2c 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -510,8 +510,8 @@ ao_lisp_frame_ref(struct ao_lisp_frame *frame, ao_poly atom); struct ao_lisp_frame * ao_lisp_frame_new(int num); -struct ao_lisp_frame * -ao_lisp_frame_add(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val); +int +ao_lisp_frame_add(struct ao_lisp_frame **frame, ao_poly atom, ao_poly val); void ao_lisp_frame_print(ao_poly p); @@ -538,8 +538,7 @@ ao_poly ao_lisp_macro(struct ao_lisp_cons *cons); ao_poly -ao_lisp_lambda_eval(struct ao_lisp_lambda *lambda, - struct ao_lisp_cons *cons); +ao_lisp_lambda_eval(void); /* error */ diff --git a/src/lisp/ao_lisp_atom.c b/src/lisp/ao_lisp_atom.c index 5c6d5a67..efa4f621 100644 --- a/src/lisp/ao_lisp_atom.c +++ b/src/lisp/ao_lisp_atom.c @@ -147,7 +147,7 @@ ao_lisp_atom_set(ao_poly atom, ao_poly val) if (ref) *ref = val; else - ao_lisp_frame_global = ao_lisp_frame_add(ao_lisp_frame_global, atom, val); + ao_lisp_frame_add(&ao_lisp_frame_global, atom, val); return val; } diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c index 855079b8..cd8a8d1d 100644 --- a/src/lisp/ao_lisp_cons.c +++ b/src/lisp/ao_lisp_cons.c @@ -67,7 +67,13 @@ const struct ao_lisp_type ao_lisp_cons_type = { struct ao_lisp_cons * ao_lisp_cons_cons(ao_poly car, struct ao_lisp_cons *cdr) { - struct ao_lisp_cons *cons = ao_lisp_alloc(sizeof (struct ao_lisp_cons)); + struct ao_lisp_cons *cons; + + ao_lisp_root_add(&ao_lisp_cons_type, &cdr); + ao_lisp_root_poly_add(&car); + cons = ao_lisp_alloc(sizeof (struct ao_lisp_cons)); + ao_lisp_root_clear(&car); + ao_lisp_root_clear(&cdr); if (!cons) return NULL; cons->car = car; diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index c5addcb0..ae2436b8 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -12,7 +12,7 @@ * General Public License for more details. */ -#define DBG_EVAL 1 +#define DBG_EVAL 0 #include "ao_lisp.h" #include @@ -46,19 +46,20 @@ stack_move(void *addr) struct ao_lisp_stack *stack = addr; while (stack) { - void *prev; + struct ao_lisp_stack *prev; int ret; (void) ao_lisp_poly_move(&stack->sexprs, 0); (void) ao_lisp_poly_move(&stack->values, 0); (void) ao_lisp_poly_move(&stack->values_tail, 0); (void) ao_lisp_poly_move(&stack->frame, 0); prev = ao_lisp_poly_stack(stack->prev); - ret = ao_lisp_move(&ao_lisp_stack_type, &prev); + ret = ao_lisp_move_memory((void **) &prev, + sizeof (struct ao_lisp_stack)); if (prev != ao_lisp_poly_stack(stack->prev)) stack->prev = ao_lisp_stack_poly(prev); if (ret) break; - stack = ao_lisp_poly_stack(stack->prev); + stack = prev; } } @@ -101,8 +102,8 @@ ao_lisp_stack_push(void) ao_lisp_stack = stack; ao_lisp_stack_reset(stack); DBGI("stack push\n"); - DBG_IN(); DBG_FRAMES(); + DBG_IN(); return 1; } @@ -236,37 +237,11 @@ static int ao_lisp_eval_val(void) { DBGI("val: "); DBG_POLY(ao_lisp_v); DBG("\n"); -#if 0 - if (ao_lisp_stack->macro) { - DBGI(".. end macro %d\n", ao_lisp_stack->macro); - DBGI(".. sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); - DBGI(".. values "); DBG_POLY(ao_lisp_stack->values); DBG("\n"); - ao_lisp_frames_dump(); - - ao_lisp_stack_pop(); -#if 0 - /* - * Re-use the current stack to evaluate - * the value from the macro - */ - ao_lisp_stack->state = eval_sexpr; - ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->macro_frame); - ao_lisp_stack->frame = ao_lisp_stack->macro_frame; - ao_lisp_stack->macro = 0; - ao_lisp_stack->macro_frame = AO_LISP_NIL; - ao_lisp_stack->sexprs = AO_LISP_NIL; - ao_lisp_stack->values = AO_LISP_NIL; - ao_lisp_stack->values_tail = AO_LISP_NIL; -#endif - } else -#endif - { - /* - * Value computed, pop the stack - * to figure out what to do with the value - */ - ao_lisp_stack_pop(); - } + /* + * Value computed, pop the stack + * to figure out what to do with the value + */ + ao_lisp_stack_pop(); DBGI("..state %d\n", ao_lisp_stack ? ao_lisp_stack->state : -1); return 1; } @@ -305,7 +280,6 @@ ao_lisp_eval_formal(void) break; case AO_LISP_FUNC_MACRO: /* Evaluate the result once more */ - prev = ao_lisp_stack; ao_lisp_stack->state = eval_sexpr; if (!ao_lisp_stack_push()) return 0; @@ -313,6 +287,7 @@ ao_lisp_eval_formal(void) /* After the function returns, take that * value and re-evaluate it */ + prev = ao_lisp_poly_stack(ao_lisp_stack->prev); ao_lisp_stack->state = eval_sexpr; ao_lisp_stack->sexprs = prev->sexprs; prev->sexprs = AO_LISP_NIL; @@ -400,8 +375,7 @@ ao_lisp_eval_exec(void) case AO_LISP_LAMBDA: ao_lisp_stack->state = eval_sexpr; DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); - ao_lisp_v = ao_lisp_lambda_eval(ao_lisp_poly_lambda(ao_lisp_v), - ao_lisp_poly_cons(ao_lisp_stack->values)); + ao_lisp_v = ao_lisp_lambda_eval(); DBGI(".. sexpr "); DBG_POLY(ao_lisp_v); DBG("\n"); DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); break; @@ -464,12 +438,11 @@ ao_lisp_eval_cond_test(void) struct ao_lisp_cons *car = ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car); struct ao_lisp_cons *c = ao_lisp_poly_cons(car->cdr); - ao_lisp_stack->state = eval_val; if (c) { + ao_lisp_stack->state = eval_sexpr; ao_lisp_v = c->car; - if (!ao_lisp_stack_push()) - return 0; - } + } else + ao_lisp_stack->state = eval_val; } else { ao_lisp_stack->sexprs = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr; DBGI("next cond: "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); diff --git a/src/lisp/ao_lisp_frame.c b/src/lisp/ao_lisp_frame.c index 7978f20a..90344719 100644 --- a/src/lisp/ao_lisp_frame.c +++ b/src/lisp/ao_lisp_frame.c @@ -174,8 +174,9 @@ ao_lisp_frame_new(int num) } static struct ao_lisp_frame * -ao_lisp_frame_realloc(struct ao_lisp_frame *frame, int new_num) +ao_lisp_frame_realloc(struct ao_lisp_frame **frame_ref, int new_num) { + struct ao_lisp_frame *frame = *frame_ref; struct ao_lisp_frame *new; int copy; @@ -184,34 +185,45 @@ ao_lisp_frame_realloc(struct ao_lisp_frame *frame, int new_num) new = ao_lisp_frame_new(new_num); if (!new) return NULL; + /* + * Re-fetch the frame as it may have moved + * during the allocation + */ + frame = *frame_ref; copy = new_num; if (copy > frame->num) copy = frame->num; memcpy(new->vals, frame->vals, copy * sizeof (struct ao_lisp_val)); - if (frame) - new->next = frame->next; + new->next = frame->next; return new; } -struct ao_lisp_frame * -ao_lisp_frame_add(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val) +int +ao_lisp_frame_add(struct ao_lisp_frame **frame_ref, ao_poly atom, ao_poly val) { + struct ao_lisp_frame *frame = *frame_ref; ao_poly *ref = frame ? ao_lisp_frame_ref(frame, atom) : NULL; + if (!ref) { int f; + ao_lisp_root_poly_add(&atom); + ao_lisp_root_poly_add(&val); if (frame) { f = frame->num; - frame = ao_lisp_frame_realloc(frame, f + 1); + frame = ao_lisp_frame_realloc(frame_ref, f + 1); } else { f = 0; frame = ao_lisp_frame_new(1); } + ao_lisp_root_clear(&atom); + ao_lisp_root_clear(&val); if (!frame) - return NULL; + return 0; + *frame_ref = frame; DBG ("add atom %s %d, val %d at %d\n", ao_lisp_poly_atom(atom)->name, OFFSET(atom), OFFSET(val), f); frame->vals[f].atom = atom; ref = &frame->vals[f].val; } *ref = val; - return frame; + return 1; } diff --git a/src/lisp/ao_lisp_lambda.c b/src/lisp/ao_lisp_lambda.c index cc5af4bc..8eafb187 100644 --- a/src/lisp/ao_lisp_lambda.c +++ b/src/lisp/ao_lisp_lambda.c @@ -133,18 +133,17 @@ ao_lisp_macro(struct ao_lisp_cons *cons) } ao_poly -ao_lisp_lambda_eval(struct ao_lisp_lambda *lambda, - struct ao_lisp_cons *cons) +ao_lisp_lambda_eval(void) { - struct ao_lisp_cons *code; - struct ao_lisp_cons *args; + struct ao_lisp_lambda *lambda = ao_lisp_poly_lambda(ao_lisp_v); + struct ao_lisp_cons *cons = ao_lisp_poly_cons(ao_lisp_stack->values); + struct ao_lisp_cons *code = ao_lisp_poly_cons(lambda->code); + struct ao_lisp_cons *args = ao_lisp_poly_cons(ao_lisp_arg(code, 0)); struct ao_lisp_frame *next_frame; int args_wanted; int args_provided; - code = ao_lisp_poly_cons(lambda->code); DBGI("lambda "); DBG_POLY(ao_lisp_lambda_poly(lambda)); DBG("\n"); - args = ao_lisp_poly_cons(ao_lisp_arg(code, 0)); args_wanted = ao_lisp_cons_length(args); @@ -156,7 +155,15 @@ ao_lisp_lambda_eval(struct ao_lisp_lambda *lambda, args_provided = 1; if (args_wanted != args_provided) return ao_lisp_error(AO_LISP_INVALID, "need %d args, not %d", args_wanted, args_provided); + next_frame = ao_lisp_frame_new(args_wanted); + + /* Re-fetch all of the values in case something moved */ + lambda = ao_lisp_poly_lambda(ao_lisp_v); + cons = ao_lisp_poly_cons(ao_lisp_stack->values); + code = ao_lisp_poly_cons(lambda->code); + args = ao_lisp_poly_cons(ao_lisp_arg(code, 0)); + switch (lambda->args) { case AO_LISP_FUNC_LAMBDA: { int f; diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 66e09db0..b763d78b 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -28,32 +28,33 @@ uint8_t ao_lisp_pool[AO_LISP_POOL] __attribute__((aligned(4))); #endif #if 0 -#define DBG_COLLECT_ALWAYS +#define MDBG_COLLECT_ALWAYS #endif #if 0 -#define DBG_POOL +#define MDBG_POOL #endif #if 0 -#define DBG_INCLUDE -#define DBG_DUMP 0 -#define DBG_OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_pool)) -#define DBG(...) printf(__VA_ARGS__) -#define DBG_DO(a) a -static int move_dump = 1; +#define MDBG_INCLUDE +#define MDBG_DUMP 1 +#define MDBG_MOVE 0 +#define MDBG_OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_pool)) +#define MDBG(...) printf(__VA_ARGS__) +#define MDBG_DO(a) a +static int move_dump = MDBG_MOVE; static int move_depth; -#define DBG_RESET() (move_depth = 0) -#define DBG_MOVE(...) do { if(move_dump) { int d; for (d = 0; d < move_depth; d++) printf (" "); printf(__VA_ARGS__); } } while (0) -#define DBG_MOVE_IN() (move_depth++) -#define DBG_MOVE_OUT() (move_depth--) +#define MDBG_RESET() (move_depth = 0) +#define MDBG_MOVE(...) do { if(move_dump) { int d; for (d = 0; d < move_depth; d++) printf (" "); printf(__VA_ARGS__); } } while (0) +#define MDBG_MOVE_IN() (move_depth++) +#define MDBG_MOVE_OUT() (move_depth--) #else -#define DBG(...) -#define DBG_DO(a) -#define DBG_RESET() -#define DBG_MOVE(...) -#define DBG_MOVE_IN() -#define DBG_MOVE_OUT() +#define MDBG(...) +#define MDBG_DO(a) +#define MDBG_RESET() +#define MDBG_MOVE(...) +#define MDBG_MOVE_IN() +#define MDBG_MOVE_OUT() #endif uint8_t ao_lisp_exception; @@ -69,7 +70,7 @@ static struct ao_lisp_root ao_lisp_root[AO_LISP_ROOT]; static uint8_t ao_lisp_busy[AO_LISP_POOL / 32]; static uint8_t ao_lisp_moving[AO_LISP_POOL / 32]; -static uint8_t ao_lisp_cons[AO_LISP_POOL / 32]; +static uint8_t ao_lisp_cons_note[AO_LISP_POOL / 32]; static uint8_t ao_lisp_cons_last[AO_LISP_POOL / 32]; static uint8_t ao_lisp_cons_noted; @@ -78,6 +79,7 @@ uint16_t ao_lisp_top; static inline void mark(uint8_t *tag, int offset) { int byte = offset >> 5; int bit = (offset >> 2) & 7; + tag[byte] |= (1 << bit); } @@ -166,10 +168,11 @@ busy_object(uint8_t *tag, void *addr) { static void note_cons(void *addr) { - DBG_MOVE("note cons %d\n", DBG_OFFSET(addr)); + MDBG_MOVE("note cons %d\n", MDBG_OFFSET(addr)); if (AO_LISP_IS_POOL(addr)) { + int offset = (uint8_t *) addr - ao_lisp_pool; ao_lisp_cons_noted = 1; - mark(ao_lisp_cons, (uint8_t *) addr - ao_lisp_pool); + mark(ao_lisp_cons_note, offset); } } @@ -182,11 +185,11 @@ move_object(void) { int i; - DBG_RESET(); - DBG_MOVE("move %d -> %d\n", DBG_OFFSET(move_old), DBG_OFFSET(move_new)); - DBG_MOVE_IN(); + MDBG_RESET(); + MDBG_MOVE("move %d -> %d\n", MDBG_OFFSET(move_old), MDBG_OFFSET(move_new)); + MDBG_MOVE_IN(); memset(ao_lisp_moving, '\0', sizeof (ao_lisp_moving)); - memset(ao_lisp_cons, '\0', sizeof (ao_lisp_cons)); + memset(ao_lisp_cons_note, '\0', sizeof (ao_lisp_cons_note)); ao_lisp_cons_noted = 0; for (i = 0; i < AO_LISP_ROOT; i++) { if (!ao_lisp_root[i].addr) @@ -195,10 +198,10 @@ move_object(void) void *addr = *ao_lisp_root[i].addr; if (!addr) continue; - DBG_MOVE("root %d\n", DBG_OFFSET(addr)); + MDBG_MOVE("root %d\n", MDBG_OFFSET(addr)); if (!ao_lisp_move(ao_lisp_root[i].type, ao_lisp_root[i].addr)) { - DBG_MOVE("root moves from %p to %p\n", + MDBG_MOVE("root moves from %p to %p\n", addr, *ao_lisp_root[i].addr); } @@ -207,31 +210,31 @@ move_object(void) if (!p) continue; if (!ao_lisp_poly_move((ao_poly *) ao_lisp_root[i].addr, 0)) { - DBG_MOVE("root poly move from %04x to %04x\n", + MDBG_MOVE("root poly move from %04x to %04x\n", p, *(ao_poly *) ao_lisp_root[i].addr); } } } while (ao_lisp_cons_noted) { - memcpy(ao_lisp_cons_last, ao_lisp_cons, sizeof (ao_lisp_cons)); - memset(ao_lisp_cons, '\0', sizeof (ao_lisp_cons)); + memcpy(ao_lisp_cons_last, ao_lisp_cons_note, sizeof (ao_lisp_cons_note)); + memset(ao_lisp_cons_note, '\0', sizeof (ao_lisp_cons_note)); ao_lisp_cons_noted = 0; for (i = 0; i < AO_LISP_POOL; i += 4) { if (busy(ao_lisp_cons_last, i)) { void *addr = ao_lisp_pool + i; - DBG_MOVE("cons %d\n", DBG_OFFSET(addr)); + MDBG_MOVE("cons %d\n", MDBG_OFFSET(addr)); if (!ao_lisp_move(&ao_lisp_cons_type, &addr)) { - DBG_MOVE("cons moves from %p to %p\n", + MDBG_MOVE("cons moves from %p to %p\n", ao_lisp_pool + i, addr); } } } } - DBG_MOVE_OUT(); - DBG_MOVE("move done\n"); + MDBG_MOVE_OUT(); + MDBG_MOVE("move done\n"); } -#if DBG_DUMP +#if MDBG_DUMP static void dump_busy(void) { @@ -272,32 +275,32 @@ ao_lisp_mark_busy(void) int i; memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy)); - memset(ao_lisp_cons, '\0', sizeof (ao_lisp_cons)); + memset(ao_lisp_cons_note, '\0', sizeof (ao_lisp_cons_note)); ao_lisp_cons_noted = 0; - DBG("mark\n"); + MDBG("mark\n"); for (i = 0; i < AO_LISP_ROOT; i++) { if (ao_lisp_root[i].type) { void **a = ao_lisp_root[i].addr, *v; if (a && (v = *a)) { - DBG("root %d\n", DBG_OFFSET(v)); + MDBG("root %d\n", MDBG_OFFSET(v)); ao_lisp_mark(ao_lisp_root[i].type, v); } } else { ao_poly *a = (ao_poly *) ao_lisp_root[i].addr, p; if (a && (p = *a)) { - DBG("root 0x%04x\n", p); + MDBG("root 0x%04x\n", p); ao_lisp_poly_mark(p, 0); } } } while (ao_lisp_cons_noted) { - memcpy(ao_lisp_cons_last, ao_lisp_cons, sizeof (ao_lisp_cons)); - memset(ao_lisp_cons, '\0', sizeof (ao_lisp_cons)); + memcpy(ao_lisp_cons_last, ao_lisp_cons_note, sizeof (ao_lisp_cons_note)); + memset(ao_lisp_cons_note, '\0', sizeof (ao_lisp_cons_note)); ao_lisp_cons_noted = 0; for (i = 0; i < AO_LISP_POOL; i += 4) { if (busy(ao_lisp_cons_last, i)) { void *v = ao_lisp_pool + i; - DBG("cons %d\n", DBG_OFFSET(v)); + MDBG("cons %d\n", MDBG_OFFSET(v)); ao_lisp_mark(&ao_lisp_cons_type, v); } } @@ -310,13 +313,13 @@ ao_lisp_collect(void) int i; int top; - DBG("collect\n"); + MDBG("collect\n"); /* Mark */ ao_lisp_mark_busy(); DUMP_BUSY(); /* Compact */ - DBG("find first busy\n"); + MDBG("find first busy\n"); for (i = 0; i < ao_lisp_top; i += 4) { if (!busy(ao_lisp_busy, i)) break; @@ -324,23 +327,25 @@ ao_lisp_collect(void) top = i; while(i < ao_lisp_top) { if (busy(ao_lisp_busy, i)) { - DBG("busy %d -> %d\n", i, top); + MDBG("busy %d -> %d\n", i, top); move_old = &ao_lisp_pool[i]; move_new = &ao_lisp_pool[top]; move_size = 0; move_object(); - DBG("\tbusy size %d\n", move_size); + MDBG("\tbusy size %d\n", move_size); if (move_size == 0) ao_lisp_abort(); clear_object(ao_lisp_busy, move_old, move_size); mark_object(ao_lisp_busy, move_new, move_size); - if (busy_object(ao_lisp_cons, move_old)) { - clear_object(ao_lisp_cons, move_old, move_size); - mark_object(ao_lisp_cons, move_new, move_size); + if (busy_object(ao_lisp_cons_note, move_old)) { + clear_object(ao_lisp_cons_note, move_old, move_size); + mark_object(ao_lisp_cons_note, move_new, move_size); } i += move_size; top += move_size; +#if MDBG_MOVE DUMP_BUSY(); +#endif } else { i += 4; } @@ -404,9 +409,9 @@ static void * check_move(void *addr, int size) { if (addr == move_old) { - DBG_MOVE("mapping %d -> %d\n", DBG_OFFSET(addr), DBG_OFFSET(move_new)); + MDBG_MOVE("mapping %d -> %d\n", MDBG_OFFSET(addr), MDBG_OFFSET(move_new)); if (!busy_object(ao_lisp_moving, addr)) { - DBG_MOVE(" copy %d\n", size); + MDBG_MOVE(" copy %d\n", size); memmove(move_new, move_old, size); move_size = (size + 3) & ~3; } @@ -429,24 +434,24 @@ ao_lisp_move(const struct ao_lisp_type *type, void **ref) if (AO_LISP_IS_CONST(addr)) return 1; #endif - DBG_MOVE("object %d\n", DBG_OFFSET(addr)); + MDBG_MOVE("object %d\n", MDBG_OFFSET(addr)); if (!AO_LISP_IS_POOL(a)) ao_lisp_abort(); - DBG_MOVE_IN(); + MDBG_MOVE_IN(); addr = check_move(addr, size); if (addr != *ref) *ref = addr; if (mark_object(ao_lisp_moving, addr, size)) { - DBG_MOVE("already moved\n"); - DBG_MOVE_OUT(); + MDBG_MOVE("already moved\n"); + MDBG_MOVE_OUT(); return 1; } - DBG_MOVE_OUT(); - DBG_MOVE("recursing...\n"); - DBG_MOVE_IN(); + MDBG_MOVE_OUT(); + MDBG_MOVE("recursing...\n"); + MDBG_MOVE_IN(); type->move(addr); - DBG_MOVE_OUT(); - DBG_MOVE("done %d\n", DBG_OFFSET(addr)); + MDBG_MOVE_OUT(); + MDBG_MOVE("done %d\n", MDBG_OFFSET(addr)); return 0; } @@ -457,17 +462,17 @@ ao_lisp_move_memory(void **ref, int size) if (!addr) return 1; - DBG_MOVE("memory %d\n", DBG_OFFSET(addr)); - DBG_MOVE_IN(); + MDBG_MOVE("memory %d\n", MDBG_OFFSET(addr)); + MDBG_MOVE_IN(); addr = check_move(addr, size); if (addr != *ref) *ref = addr; if (mark_object(ao_lisp_moving, addr, size)) { - DBG_MOVE("already moved\n"); - DBG_MOVE_OUT(); + MDBG_MOVE("already moved\n"); + MDBG_MOVE_OUT(); return 1; } - DBG_MOVE_OUT(); + MDBG_MOVE_OUT(); return 0; } @@ -505,14 +510,14 @@ ao_lisp_poly_move(ao_poly *ref, uint8_t do_note_cons) if (addr != ao_lisp_ref(p)) { ao_poly np = ao_lisp_poly(addr, p & AO_LISP_TYPE_MASK); - DBG("poly %d moved %04x -> %04x\n", + MDBG("poly %d moved %04x -> %04x\n", type, p, np); *ref = np; } return ret; } -#ifdef DBG_POOL +#ifdef MDBG_POOL static int AO_LISP_POOL_CUR = AO_LISP_POOL / 8; static void @@ -557,18 +562,18 @@ ao_lisp_alloc(int size) void *addr; size = ao_lisp_mem_round(size); -#ifdef DBG_COLLECT_ALWAYS +#ifdef MDBG_COLLECT_ALWAYS ao_lisp_collect(); #endif if (ao_lisp_top + size > AO_LISP_POOL_CUR) { -#ifdef DBG_POOL +#ifdef MDBG_POOL if (AO_LISP_POOL_CUR < AO_LISP_POOL) { AO_LISP_POOL_CUR += AO_LISP_POOL / 8; ao_lisp_poison(); } else #endif ao_lisp_collect(); -#ifdef DBG_POOL +#ifdef MDBG_POOL { int i; @@ -580,7 +585,7 @@ ao_lisp_alloc(int size) #endif if (ao_lisp_top + size > AO_LISP_POOL) { - ao_lisp_exception |= AO_LISP_OOM; + ao_lisp_error(AO_LISP_OOM, "out of memory"); return NULL; } } @@ -593,7 +598,7 @@ int ao_lisp_root_add(const struct ao_lisp_type *type, void *addr) { int i; - DBG("add root type %p addr %p\n", type, addr); + MDBG("add root type %p addr %p\n", type, addr); for (i = 0; i < AO_LISP_ROOT; i++) { if (!ao_lisp_root[i].addr) { ao_lisp_root[i].addr = addr; -- cgit v1.2.3 From f5a36c15f894803f8804bbc3daf105eed53d5ff6 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 10 Nov 2016 23:31:10 -0800 Subject: altos/lisp: Add towers of hanoi example Uses vt100 escape sequences to animate the display even. Signed-off-by: Keith Packard --- src/test/hanoi.lisp | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 src/test/hanoi.lisp (limited to 'src') diff --git a/src/test/hanoi.lisp b/src/test/hanoi.lisp new file mode 100644 index 00000000..93594c43 --- /dev/null +++ b/src/test/hanoi.lisp @@ -0,0 +1,127 @@ +(defun move-to (col row) + (patom "\033[" row ";" col "H" nil) + ) + +(defun clear () + (patom "\033[2J" nil) + ) + +(defun test () + (clear) + (move-to 30 12) + (patom "hello, world") + (move-to 0 19) + ) + +(setq stack '("*" "**" "***" "****" "*****" "******" "*******")) + +(setq stacks nil) + +(defun display-string (x y str) + (move-to x y) + (move-to x y) + (patom str) + ) + +(defun display-stack (x y stack) + (cond (stack (progn + (display-string x y (car stack)) + (display-stack x (1+ y) (cdr stack))))) + ) + +(defun clear-stack (x y) + (cond ((> y 0) (progn + (move-to x y) + (patom " ") + (clear-stack x (1- y)) + ) + ) + ) + ) + +(defun length (list) + (cond (list (1+ (length (cdr list)))) + (0) + ) + ) + +(defun stack-pos (y stack) + (- y (length stack)) + ) + +(defun display-stacks (x y stacks) + (cond (stacks (progn + (clear-stack x 20) + (display-stack x (stack-pos y (car stacks)) (car stacks)) + (display-stacks (+ x 20) y (cdr stacks))) + ) + ) + ) + +(defun display () + (display-stacks 0 20 stacks) + (move-to 1 1) + (patom "\n") + ) + +(defun length (l) + (cond (l (1+ (length (cdr l)))) (0)) + ) + +(defun reset-stacks () + (setq stacks (list stack nil nil)) + (length stack) + ) + +(defun min (a b) + (cond ((< a b) a) + (b) + ) + ) + +(defun nth (list n) + (cond ((= n 0) (car list)) + ((nth (cdr list) (1- n))) + ) + ) + +(defun replace (list pos member) + (cond ((= pos 0) (cons member (cdr list))) + ((cons (car list) (replace (cdr list) (1- pos) member))) + ) + ) + +(defun move-piece (from to) + (let ((from-stack (nth stacks from)) + (to-stack (nth stacks to)) + (piece (car from-stack))) + (setq from-stack (cdr from-stack)) + (setq to-stack (cons piece to-stack)) + (setq stacks (replace stacks from from-stack)) + (setq stacks (replace stacks to to-stack)) + (display) + (delay 500) + ) + ) + +(defun _hanoi (n from to use) + (cond ((= 1 n) + (progn + (move-piece from to) + nil) + ) + (t + (progn + (_hanoi (1- n) from use to) + (_hanoi 1 from to use) + (_hanoi (1- n) use to from) + ) + ) + ) + ) + +(defun hanoi () + (setq len (reset-stacks)) + (clear) + (_hanoi len 0 1 2) + ) -- cgit v1.2.3 From 7f7e2431f5d1f7c1782ed6e774ccfc70fb4c87cf Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 11 Nov 2016 00:28:31 -0800 Subject: altos/lisp: add length, pack, unpack and flush lots more builtins Signed-off-by: Keith Packard --- src/lambdakey-v1.0/ao_lisp_os.h | 6 +++++ src/lisp/ao_lisp.h | 17 ++++++++++++++ src/lisp/ao_lisp_builtin.c | 47 +++++++++++++++++++++++++++++++++++++ src/lisp/ao_lisp_cons.c | 11 +++++++++ src/lisp/ao_lisp_lambda.c | 11 --------- src/lisp/ao_lisp_make_const.c | 4 ++++ src/lisp/ao_lisp_os.h | 5 ++++ src/lisp/ao_lisp_string.c | 52 +++++++++++++++++++++++++++++++++++++---- src/test/ao_lisp_os.h | 5 ++++ 9 files changed, 142 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/lambdakey-v1.0/ao_lisp_os.h b/src/lambdakey-v1.0/ao_lisp_os.h index df158f6a..1993ac44 100644 --- a/src/lambdakey-v1.0/ao_lisp_os.h +++ b/src/lambdakey-v1.0/ao_lisp_os.h @@ -35,6 +35,12 @@ ao_lisp_getc() { return c; } +static inline void +ao_lisp_os_flush(void) +{ + flush(); +} + static inline void ao_lisp_abort(void) { diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 60a97f2c..86a5ddcf 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -36,10 +36,14 @@ extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST]; #define _ao_lisp_atom_cdr _atom("cdr") #define _ao_lisp_atom_cons _atom("cons") #define _ao_lisp_atom_last _atom("last") +#define _ao_lisp_atom_length _atom("length") #define _ao_lisp_atom_cond _atom("cond") #define _ao_lisp_atom_lambda _atom("lambda") #define _ao_lisp_atom_led _atom("led") #define _ao_lisp_atom_delay _atom("delay") +#define _ao_lisp_atom_pack _atom("pack") +#define _ao_lisp_atom_unpack _atom("unpack") +#define _ao_lisp_atom_flush _atom("flush") #define _ao_lisp_atom_eval _atom("eval") #define _ao_lisp_atom_read _atom("read") #define _ao_lisp_atom_eof _atom("eof") @@ -215,6 +219,7 @@ enum ao_lisp_builtin_id { builtin_cdr, builtin_cons, builtin_last, + builtin_length, builtin_quote, builtin_set, builtin_setq, @@ -233,6 +238,9 @@ enum ao_lisp_builtin_id { builtin_greater, builtin_less_equal, builtin_greater_equal, + builtin_pack, + builtin_unpack, + builtin_flush, builtin_delay, builtin_led, _builtin_last @@ -409,6 +417,9 @@ ao_lisp_cons_print(ao_poly); void ao_lisp_cons_patom(ao_poly); +int +ao_lisp_cons_length(struct ao_lisp_cons *cons); + /* string */ extern const struct ao_lisp_type ao_lisp_string_type; @@ -421,6 +432,12 @@ ao_lisp_string_copy(char *a); char * ao_lisp_string_cat(char *a, char *b); +ao_poly +ao_lisp_string_pack(struct ao_lisp_cons *cons); + +ao_poly +ao_lisp_string_unpack(char *a); + void ao_lisp_string_print(ao_poly s); diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index 57d9ee10..30631980 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -58,6 +58,7 @@ static const ao_poly builtin_names[] = { [builtin_cdr] = _ao_lisp_atom_cdr, [builtin_cons] = _ao_lisp_atom_cons, [builtin_last] = _ao_lisp_atom_last, + [builtin_length] = _ao_lisp_atom_length, [builtin_quote] = _ao_lisp_atom_quote, [builtin_set] = _ao_lisp_atom_set, [builtin_setq] = _ao_lisp_atom_setq, @@ -76,6 +77,9 @@ static const ao_poly builtin_names[] = { [builtin_greater] = _ao_lisp_atom_3e, [builtin_less_equal] = _ao_lisp_atom_3c3d, [builtin_greater_equal] = _ao_lisp_atom_3e3d, + [builtin_pack] = _ao_lisp_atom_pack, + [builtin_unpack] = _ao_lisp_atom_unpack, + [builtin_flush] = _ao_lisp_atom_flush, [builtin_delay] = _ao_lisp_atom_delay, [builtin_led] = _ao_lisp_atom_led, }; @@ -200,6 +204,16 @@ ao_lisp_last(struct ao_lisp_cons *cons) return AO_LISP_NIL; } +ao_poly +ao_lisp_length(struct ao_lisp_cons *cons) +{ + if (!ao_lisp_check_argc(_ao_lisp_atom_last, cons, 1, 1)) + return AO_LISP_NIL; + if (!ao_lisp_check_argt(_ao_lisp_atom_last, cons, 0, AO_LISP_CONS, 1)) + return AO_LISP_NIL; + return ao_lisp_int_poly(ao_lisp_cons_length(ao_lisp_poly_cons(ao_lisp_arg(cons, 0)))); +} + ao_poly ao_lisp_quote(struct ao_lisp_cons *cons) { @@ -470,6 +484,35 @@ ao_lisp_greater_equal(struct ao_lisp_cons *cons) return ao_lisp_compare(cons, builtin_greater_equal); } +ao_poly +ao_lisp_pack(struct ao_lisp_cons *cons) +{ + if (!ao_lisp_check_argc(_ao_lisp_atom_pack, cons, 1, 1)) + return AO_LISP_NIL; + if (!ao_lisp_check_argt(_ao_lisp_atom_pack, cons, 0, AO_LISP_CONS, 1)) + return AO_LISP_NIL; + return ao_lisp_string_pack(ao_lisp_poly_cons(ao_lisp_arg(cons, 0))); +} + +ao_poly +ao_lisp_unpack(struct ao_lisp_cons *cons) +{ + if (!ao_lisp_check_argc(_ao_lisp_atom_unpack, cons, 1, 1)) + return AO_LISP_NIL; + if (!ao_lisp_check_argt(_ao_lisp_atom_unpack, cons, 0, AO_LISP_STRING, 0)) + return AO_LISP_NIL; + return ao_lisp_string_unpack(ao_lisp_poly_string(ao_lisp_arg(cons, 0))); +} + +ao_poly +ao_lisp_flush(struct ao_lisp_cons *cons) +{ + if (!ao_lisp_check_argc(_ao_lisp_atom_flush, cons, 0, 0)) + return AO_LISP_NIL; + ao_lisp_os_flush(); + return _ao_lisp_atom_t; +} + ao_poly ao_lisp_led(struct ao_lisp_cons *cons) { @@ -524,6 +567,7 @@ const ao_lisp_func_t ao_lisp_builtins[] = { [builtin_cdr] = ao_lisp_cdr, [builtin_cons] = ao_lisp_cons, [builtin_last] = ao_lisp_last, + [builtin_length] = ao_lisp_length, [builtin_quote] = ao_lisp_quote, [builtin_set] = ao_lisp_set, [builtin_setq] = ao_lisp_setq, @@ -542,6 +586,9 @@ const ao_lisp_func_t ao_lisp_builtins[] = { [builtin_greater] = ao_lisp_greater, [builtin_less_equal] = ao_lisp_less_equal, [builtin_greater_equal] = ao_lisp_greater_equal, + [builtin_pack] = ao_lisp_pack, + [builtin_unpack] = ao_lisp_unpack, + [builtin_flush] = ao_lisp_flush, [builtin_led] = ao_lisp_led, [builtin_delay] = ao_lisp_delay, }; diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c index cd8a8d1d..b75ffaa0 100644 --- a/src/lisp/ao_lisp_cons.c +++ b/src/lisp/ao_lisp_cons.c @@ -107,3 +107,14 @@ ao_lisp_cons_patom(ao_poly c) cons = ao_lisp_poly_cons(cons->cdr); } } + +int +ao_lisp_cons_length(struct ao_lisp_cons *cons) +{ + int len = 0; + while (cons) { + len++; + cons = ao_lisp_poly_cons(cons->cdr); + } + return len; +} diff --git a/src/lisp/ao_lisp_lambda.c b/src/lisp/ao_lisp_lambda.c index 8eafb187..c53a38fd 100644 --- a/src/lisp/ao_lisp_lambda.c +++ b/src/lisp/ao_lisp_lambda.c @@ -49,17 +49,6 @@ const struct ao_lisp_type ao_lisp_lambda_type = { .move = lambda_move, }; -static int -ao_lisp_cons_length(struct ao_lisp_cons *cons) -{ - int len = 0; - while (cons) { - len++; - cons = ao_lisp_poly_cons(cons->cdr); - } - return len; -} - void ao_lisp_lambda_print(ao_poly poly) { diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index 4fc43e58..0b3e25a6 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -43,6 +43,7 @@ struct builtin_func funcs[] = { "cdr", AO_LISP_FUNC_LAMBDA, builtin_cdr, "cons", AO_LISP_FUNC_LAMBDA, builtin_cons, "last", AO_LISP_FUNC_LAMBDA, builtin_last, + "length", AO_LISP_FUNC_LAMBDA, builtin_length, "quote", AO_LISP_FUNC_NLAMBDA, builtin_quote, "set", AO_LISP_FUNC_LAMBDA, builtin_set, "setq", AO_LISP_FUNC_MACRO, builtin_setq, @@ -61,6 +62,9 @@ struct builtin_func funcs[] = { ">", AO_LISP_FUNC_LEXPR, builtin_greater, "<=", AO_LISP_FUNC_LEXPR, builtin_less_equal, ">=", AO_LISP_FUNC_LEXPR, builtin_greater_equal, + "pack", AO_LISP_FUNC_LAMBDA, builtin_pack, + "unpack", AO_LISP_FUNC_LAMBDA, builtin_unpack, + "flush", AO_LISP_FUNC_LAMBDA, builtin_flush, "delay", AO_LISP_FUNC_LAMBDA, builtin_delay, "led", AO_LISP_FUNC_LEXPR, builtin_led, }; diff --git a/src/lisp/ao_lisp_os.h b/src/lisp/ao_lisp_os.h index 55ffed50..b7bf7a2c 100644 --- a/src/lisp/ao_lisp_os.h +++ b/src/lisp/ao_lisp_os.h @@ -27,6 +27,11 @@ ao_lisp_getc() { return getchar(); } +static inline void +ao_lisp_os_flush() { + fflush(stdout); +} + static inline void ao_lisp_abort(void) { diff --git a/src/lisp/ao_lisp_string.c b/src/lisp/ao_lisp_string.c index 0064064c..9ee1a7dd 100644 --- a/src/lisp/ao_lisp_string.c +++ b/src/lisp/ao_lisp_string.c @@ -34,6 +34,12 @@ static void string_move(void *addr) (void) addr; } +const struct ao_lisp_type ao_lisp_string_type = { + .mark = string_mark, + .size = string_size, + .move = string_move, +}; + char * ao_lisp_string_new(int len) { char *a = ao_lisp_alloc(len + 1); @@ -68,11 +74,47 @@ ao_lisp_string_cat(char *a, char *b) return r; } -const struct ao_lisp_type ao_lisp_string_type = { - .mark = string_mark, - .size = string_size, - .move = string_move, -}; +ao_poly +ao_lisp_string_pack(struct ao_lisp_cons *cons) +{ + int len = ao_lisp_cons_length(cons); + char *r = ao_lisp_alloc(len + 1); + char *s = r; + + while (cons) { + if (ao_lisp_poly_type(cons->car) != AO_LISP_INT) + return ao_lisp_error(AO_LISP_INVALID, "non-int passed to pack"); + *s++ = ao_lisp_poly_int(cons->car); + cons = ao_lisp_poly_cons(cons->cdr); + } + *s++ = 0; + return ao_lisp_string_poly(r); +} + +ao_poly +ao_lisp_string_unpack(char *a) +{ + struct ao_lisp_cons *cons = NULL, *tail = NULL; + int c; + + ao_lisp_root_add(&ao_lisp_cons_type, &cons); + ao_lisp_root_add(&ao_lisp_cons_type, &tail); + while ((c = *a++)) { + struct ao_lisp_cons *n = ao_lisp_cons_cons(ao_lisp_int_poly(c), NULL); + if (!n) { + cons = NULL; + break; + } + if (tail) + tail->cdr = ao_lisp_cons_poly(n); + else + cons = n; + tail = n; + } + ao_lisp_root_clear(&cons); + ao_lisp_root_clear(&tail); + return ao_lisp_cons_poly(cons); +} void ao_lisp_string_print(ao_poly p) diff --git a/src/test/ao_lisp_os.h b/src/test/ao_lisp_os.h index 19bd4f64..c979697e 100644 --- a/src/test/ao_lisp_os.h +++ b/src/test/ao_lisp_os.h @@ -24,6 +24,11 @@ extern int ao_lisp_getc(void); +static inline void +ao_lisp_os_flush() { + fflush(stdout); +} + static inline void ao_lisp_abort(void) { -- cgit v1.2.3 From 00827a0ffe30938c26be216369fd2d8f8946d2c4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 11 Nov 2016 00:28:57 -0800 Subject: altos/lisp: Share mark function for mark and move These two operations both wanted to walk the referenced objects; sharing is caring. Signed-off-by: Keith Packard --- src/lambdakey-v1.0/Makefile | 4 +- src/lisp/ao_lisp_mem.c | 108 ++++++++++++++++---------------------------- src/test/hanoi.lisp | 8 ++-- 3 files changed, 48 insertions(+), 72 deletions(-) (limited to 'src') diff --git a/src/lambdakey-v1.0/Makefile b/src/lambdakey-v1.0/Makefile index ef03527e..1ac04f24 100644 --- a/src/lambdakey-v1.0/Makefile +++ b/src/lambdakey-v1.0/Makefile @@ -56,6 +56,8 @@ IDPRODUCT=0x000a CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -Os -g +LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Tlambda.ld + PROGNAME=lambdakey-v1.0 PROG=$(PROGNAME)-$(VERSION).elf HEX=$(PROGNAME)-$(VERSION).ihx @@ -65,7 +67,7 @@ OBJ=$(SRC:.c=.o) all: $(PROG) $(HEX) -$(PROG): Makefile $(OBJ) altos.ld +$(PROG): Makefile $(OBJ) lambda.ld altos.ld $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) $(OBJ): $(INC) diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index b763d78b..1fb1b459 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -79,7 +79,6 @@ uint16_t ao_lisp_top; static inline void mark(uint8_t *tag, int offset) { int byte = offset >> 5; int bit = (offset >> 2) & 7; - tag[byte] |= (1 << bit); } @@ -176,42 +175,32 @@ note_cons(void *addr) } } - -static void *move_old, *move_new; -static int move_size; +/* + * Walk all referenced objects calling functions on each one + */ static void -move_object(void) +walk_all(uint8_t *tag, + int (*visit_addr)(const struct ao_lisp_type *type, void **addr), + int (*visit_poly)(ao_poly *p, uint8_t do_note_cons)) { - int i; + int i; - MDBG_RESET(); - MDBG_MOVE("move %d -> %d\n", MDBG_OFFSET(move_old), MDBG_OFFSET(move_new)); - MDBG_MOVE_IN(); - memset(ao_lisp_moving, '\0', sizeof (ao_lisp_moving)); + memset(tag, '\0', sizeof (ao_lisp_busy)); memset(ao_lisp_cons_note, '\0', sizeof (ao_lisp_cons_note)); ao_lisp_cons_noted = 0; for (i = 0; i < AO_LISP_ROOT; i++) { - if (!ao_lisp_root[i].addr) - continue; if (ao_lisp_root[i].type) { - void *addr = *ao_lisp_root[i].addr; - if (!addr) - continue; - MDBG_MOVE("root %d\n", MDBG_OFFSET(addr)); - if (!ao_lisp_move(ao_lisp_root[i].type, - ao_lisp_root[i].addr)) { - MDBG_MOVE("root moves from %p to %p\n", - addr, - *ao_lisp_root[i].addr); + void **a = ao_lisp_root[i].addr, *v; + if (a && (v = *a)) { + MDBG("root %d\n", MDBG_OFFSET(v)); + visit_addr(ao_lisp_root[i].type, a); } } else { - ao_poly p = *(ao_poly *) ao_lisp_root[i].addr; - if (!p) - continue; - if (!ao_lisp_poly_move((ao_poly *) ao_lisp_root[i].addr, 0)) { - MDBG_MOVE("root poly move from %04x to %04x\n", - p, *(ao_poly *) ao_lisp_root[i].addr); + ao_poly *a = (ao_poly *) ao_lisp_root[i].addr, p; + if (a && (p = *a)) { + MDBG("root 0x%04x\n", p); + visit_poly(a, 0); } } } @@ -221,17 +210,21 @@ move_object(void) ao_lisp_cons_noted = 0; for (i = 0; i < AO_LISP_POOL; i += 4) { if (busy(ao_lisp_cons_last, i)) { - void *addr = ao_lisp_pool + i; - MDBG_MOVE("cons %d\n", MDBG_OFFSET(addr)); - if (!ao_lisp_move(&ao_lisp_cons_type, &addr)) { - MDBG_MOVE("cons moves from %p to %p\n", - ao_lisp_pool + i, addr); - } + void *v = ao_lisp_pool + i; + MDBG("cons %d\n", MDBG_OFFSET(v)); + visit_addr(&ao_lisp_cons_type, &v); } } } - MDBG_MOVE_OUT(); - MDBG_MOVE("move done\n"); +} + +static void *move_old, *move_new; +static int move_size; + +static void +move_object(void) +{ + walk_all(ao_lisp_moving, ao_lisp_move, ao_lisp_poly_move); } #if MDBG_DUMP @@ -268,43 +261,22 @@ static const struct ao_lisp_type const *ao_lisp_types[AO_LISP_NUM_TYPE] = { [AO_LISP_LAMBDA] = &ao_lisp_lambda_type, }; +static int +ao_lisp_mark_ref(const struct ao_lisp_type *type, void **ref) +{ + return ao_lisp_mark(type, *ref); +} + +static int +ao_lisp_poly_mark_ref(ao_poly *p, uint8_t do_note_cons) +{ + return ao_lisp_poly_mark(*p, do_note_cons); +} static void ao_lisp_mark_busy(void) { - int i; - - memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy)); - memset(ao_lisp_cons_note, '\0', sizeof (ao_lisp_cons_note)); - ao_lisp_cons_noted = 0; - MDBG("mark\n"); - for (i = 0; i < AO_LISP_ROOT; i++) { - if (ao_lisp_root[i].type) { - void **a = ao_lisp_root[i].addr, *v; - if (a && (v = *a)) { - MDBG("root %d\n", MDBG_OFFSET(v)); - ao_lisp_mark(ao_lisp_root[i].type, v); - } - } else { - ao_poly *a = (ao_poly *) ao_lisp_root[i].addr, p; - if (a && (p = *a)) { - MDBG("root 0x%04x\n", p); - ao_lisp_poly_mark(p, 0); - } - } - } - while (ao_lisp_cons_noted) { - memcpy(ao_lisp_cons_last, ao_lisp_cons_note, sizeof (ao_lisp_cons_note)); - memset(ao_lisp_cons_note, '\0', sizeof (ao_lisp_cons_note)); - ao_lisp_cons_noted = 0; - for (i = 0; i < AO_LISP_POOL; i += 4) { - if (busy(ao_lisp_cons_last, i)) { - void *v = ao_lisp_pool + i; - MDBG("cons %d\n", MDBG_OFFSET(v)); - ao_lisp_mark(&ao_lisp_cons_type, v); - } - } - } + walk_all(ao_lisp_busy, ao_lisp_mark_ref, ao_lisp_poly_mark_ref); } void diff --git a/src/test/hanoi.lisp b/src/test/hanoi.lisp index 93594c43..09a3611c 100644 --- a/src/test/hanoi.lisp +++ b/src/test/hanoi.lisp @@ -60,8 +60,8 @@ (defun display () (display-stacks 0 20 stacks) - (move-to 1 1) - (patom "\n") + (move-to 1 21) + (flush) ) (defun length (l) @@ -100,7 +100,7 @@ (setq stacks (replace stacks from from-stack)) (setq stacks (replace stacks to to-stack)) (display) - (delay 500) + (delay 100) ) ) @@ -125,3 +125,5 @@ (clear) (_hanoi len 0 1 2) ) + +(hanoi) -- cgit v1.2.3 From d46ca67f93e9ecbc4d8c051c3fbdead85490b690 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 11 Nov 2016 21:07:09 -0800 Subject: altos/lisp: Make ao_lisp_ref and ao_lisp_poly non-inline These functions are pretty large and end up consuming quite a bit of space if inlined everywhere they are used. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 23 ++++------------------- src/lisp/ao_lisp_poly.c | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 86a5ddcf..7a165cd8 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -99,26 +99,11 @@ ao_lisp_is_const(ao_poly poly) { #define AO_LISP_IS_CONST(a) (ao_lisp_const <= ((uint8_t *) (a)) && ((uint8_t *) (a)) < ao_lisp_const + AO_LISP_POOL_CONST) #define AO_LISP_IS_POOL(a) (ao_lisp_pool <= ((uint8_t *) (a)) && ((uint8_t *) (a)) < ao_lisp_pool + AO_LISP_POOL) -static inline void * -ao_lisp_ref(ao_poly poly) { - if (poly == 0xBEEF) - ao_lisp_abort(); - if (poly == AO_LISP_NIL) - return NULL; - if (poly & AO_LISP_CONST) - return (void *) (AO_LISP_CONST_BASE + (poly & AO_LISP_REF_MASK)); - return (void *) (AO_LISP_POOL_BASE + (poly & AO_LISP_REF_MASK)); -} +void * +ao_lisp_ref(ao_poly poly); -static inline ao_poly -ao_lisp_poly(const void *addr, ao_poly type) { - const uint8_t *a = addr; - if (a == NULL) - return AO_LISP_NIL; - if (AO_LISP_IS_CONST(a)) - return AO_LISP_CONST | (a - AO_LISP_CONST_BASE) | type; - return (a - AO_LISP_POOL_BASE) | type; -} +ao_poly +ao_lisp_poly(const void *addr, ao_poly type); struct ao_lisp_type { int (*size)(void *addr); diff --git a/src/lisp/ao_lisp_poly.c b/src/lisp/ao_lisp_poly.c index bfd75ae3..9717fd73 100644 --- a/src/lisp/ao_lisp_poly.c +++ b/src/lisp/ao_lisp_poly.c @@ -84,3 +84,21 @@ ao_lisp_poly_patom(ao_poly p) f->patom(p); } +void * +ao_lisp_ref(ao_poly poly) { + if (poly == AO_LISP_NIL) + return NULL; + if (poly & AO_LISP_CONST) + return (void *) (AO_LISP_CONST_BASE + (poly & AO_LISP_REF_MASK)); + return (void *) (AO_LISP_POOL_BASE + (poly & AO_LISP_REF_MASK)); +} + +ao_poly +ao_lisp_poly(const void *addr, ao_poly type) { + const uint8_t *a = addr; + if (a == NULL) + return AO_LISP_NIL; + if (AO_LISP_IS_CONST(a)) + return AO_LISP_CONST | (a - AO_LISP_CONST_BASE) | type; + return (a - AO_LISP_POOL_BASE) | type; +} -- cgit v1.2.3 From 29c890b4599b3bbdbd09a5915ea68a63f4e0a9ac Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 11 Nov 2016 21:11:13 -0800 Subject: altos/lisp: Make sure memmove only happens once per object. Other GC fixes The memmove may be overlapping, so make sure it happens only once by just checking whether move_size has been set, rather than looking at ao_lisp_moving; that doesn't get set when moving a noted cons as that still needs to be walked at a later time. Fix up the various looping move functions to all use the same pattern. Atom was busted. Signed-off-by: Keith Packard --- src/lisp/ao_lisp_atom.c | 12 +++++-- src/lisp/ao_lisp_cons.c | 23 +++++++++---- src/lisp/ao_lisp_eval.c | 6 +++- src/lisp/ao_lisp_frame.c | 6 ++-- src/lisp/ao_lisp_mem.c | 85 ++++++++++++++++++++++++++---------------------- 5 files changed, 81 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp_atom.c b/src/lisp/ao_lisp_atom.c index efa4f621..e1d9b082 100644 --- a/src/lisp/ao_lisp_atom.c +++ b/src/lisp/ao_lisp_atom.c @@ -46,11 +46,19 @@ static void atom_mark(void *addr) static void atom_move(void *addr) { struct ao_lisp_atom *atom = addr; + int ret; for (;;) { - if (ao_lisp_poly_move(&atom->next, 0)) + struct ao_lisp_atom *next = ao_lisp_poly_atom(atom->next); + + if (!next) break; - atom = ao_lisp_poly_atom(atom->next); + ret = ao_lisp_move_memory((void **) &next, atom_size(next)); + if (next != ao_lisp_poly_atom(atom->next)) + atom->next = ao_lisp_atom_poly(next); + if (ret) + break; + atom = next; } } diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c index b75ffaa0..c7d8382f 100644 --- a/src/lisp/ao_lisp_cons.c +++ b/src/lisp/ao_lisp_cons.c @@ -49,6 +49,8 @@ static void cons_move(void *addr) (void) ao_lisp_poly_move(&cons->car, 1); cdr = ao_lisp_poly_cons(cons->cdr); + if (!cdr) + break; ret = ao_lisp_move_memory((void **) &cdr, sizeof (struct ao_lisp_cons)); if (cdr != ao_lisp_poly_cons(cons->cdr)) cons->cdr = ao_lisp_cons_poly(cdr); @@ -64,20 +66,29 @@ const struct ao_lisp_type ao_lisp_cons_type = { .move = cons_move, }; +static ao_poly cons_car; +static struct ao_lisp_cons *cons_cdr; +static int been_here; + struct ao_lisp_cons * ao_lisp_cons_cons(ao_poly car, struct ao_lisp_cons *cdr) { struct ao_lisp_cons *cons; - ao_lisp_root_add(&ao_lisp_cons_type, &cdr); - ao_lisp_root_poly_add(&car); + if (!been_here) { + ao_lisp_root_add(&ao_lisp_cons_type, &cons_cdr); + ao_lisp_root_poly_add(&cons_car); + been_here = 1; + } + cons_car = car; + cons_cdr = cdr; cons = ao_lisp_alloc(sizeof (struct ao_lisp_cons)); - ao_lisp_root_clear(&car); - ao_lisp_root_clear(&cdr); if (!cons) return NULL; - cons->car = car; - cons->cdr = ao_lisp_cons_poly(cdr); + cons->car = cons_car; + cons->cdr = ao_lisp_cons_poly(cons_cdr); + cons_car = AO_LISP_NIL; + cons_cdr = NULL; return cons; } diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index ae2436b8..1c929869 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -32,6 +32,7 @@ stack_mark(void *addr) ao_lisp_poly_mark(stack->values, 0); /* no need to mark values_tail */ ao_lisp_poly_mark(stack->frame, 0); + ao_lisp_poly_mark(stack->list, 0); stack = ao_lisp_poly_stack(stack->prev); if (ao_lisp_mark_memory(stack, sizeof (struct ao_lisp_stack))) break; @@ -47,12 +48,15 @@ stack_move(void *addr) while (stack) { struct ao_lisp_stack *prev; - int ret; + int ret; (void) ao_lisp_poly_move(&stack->sexprs, 0); (void) ao_lisp_poly_move(&stack->values, 0); (void) ao_lisp_poly_move(&stack->values_tail, 0); (void) ao_lisp_poly_move(&stack->frame, 0); + (void) ao_lisp_poly_move(&stack->list, 0); prev = ao_lisp_poly_stack(stack->prev); + if (!prev) + break; ret = ao_lisp_move_memory((void **) &prev, sizeof (struct ao_lisp_stack)); if (prev != ao_lisp_poly_stack(stack->prev)) diff --git a/src/lisp/ao_lisp_frame.c b/src/lisp/ao_lisp_frame.c index 90344719..082860ee 100644 --- a/src/lisp/ao_lisp_frame.c +++ b/src/lisp/ao_lisp_frame.c @@ -83,9 +83,9 @@ frame_move(void *addr) ao_lisp_poly_move(&v->val, 0); } next = ao_lisp_poly_frame(frame->next); - ret = 1; - if (next) - ret = ao_lisp_move_memory((void **) &next, frame_size(next)); + if (!next) + break; + ret = ao_lisp_move_memory((void **) &next, frame_size(next)); if (next != ao_lisp_poly_frame(frame->next)) frame->next = ao_lisp_frame_poly(next); if (ret) diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 1fb1b459..31ee9e1e 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -36,22 +36,20 @@ uint8_t ao_lisp_pool[AO_LISP_POOL] __attribute__((aligned(4))); #endif #if 0 +#include #define MDBG_INCLUDE -#define MDBG_DUMP 1 -#define MDBG_MOVE 0 +#if 1 +#define MDBG_MOVE(...) do { int d; for (d = 0; d < move_depth; d++) printf (" "); printf(__VA_ARGS__); } while (0) +#endif #define MDBG_OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_pool)) #define MDBG(...) printf(__VA_ARGS__) #define MDBG_DO(a) a -static int move_dump = MDBG_MOVE; static int move_depth; -#define MDBG_RESET() (move_depth = 0) -#define MDBG_MOVE(...) do { if(move_dump) { int d; for (d = 0; d < move_depth; d++) printf (" "); printf(__VA_ARGS__); } } while (0) #define MDBG_MOVE_IN() (move_depth++) -#define MDBG_MOVE_OUT() (move_depth--) +#define MDBG_MOVE_OUT() (assert(--move_depth >= 0)) #else #define MDBG(...) #define MDBG_DO(a) -#define MDBG_RESET() #define MDBG_MOVE(...) #define MDBG_MOVE_IN() #define MDBG_MOVE_OUT() @@ -68,10 +66,12 @@ struct ao_lisp_root { static struct ao_lisp_root ao_lisp_root[AO_LISP_ROOT]; -static uint8_t ao_lisp_busy[AO_LISP_POOL / 32]; -static uint8_t ao_lisp_moving[AO_LISP_POOL / 32]; -static uint8_t ao_lisp_cons_note[AO_LISP_POOL / 32]; -static uint8_t ao_lisp_cons_last[AO_LISP_POOL / 32]; +#define AO_LISP_BUSY_SIZE ((AO_LISP_POOL + 31) / 32) + +static uint8_t ao_lisp_busy[AO_LISP_BUSY_SIZE]; +static uint8_t ao_lisp_moving[AO_LISP_BUSY_SIZE]; +static uint8_t ao_lisp_cons_note[AO_LISP_BUSY_SIZE]; +static uint8_t ao_lisp_cons_last[AO_LISP_BUSY_SIZE]; static uint8_t ao_lisp_cons_noted; uint16_t ao_lisp_top; @@ -167,9 +167,9 @@ busy_object(uint8_t *tag, void *addr) { static void note_cons(void *addr) { - MDBG_MOVE("note cons %d\n", MDBG_OFFSET(addr)); if (AO_LISP_IS_POOL(addr)) { int offset = (uint8_t *) addr - ao_lisp_pool; + MDBG_MOVE("note cons %d\n", MDBG_OFFSET(addr)); ao_lisp_cons_noted = 1; mark(ao_lisp_cons_note, offset); } @@ -180,9 +180,9 @@ note_cons(void *addr) */ static void -walk_all(uint8_t *tag, - int (*visit_addr)(const struct ao_lisp_type *type, void **addr), - int (*visit_poly)(ao_poly *p, uint8_t do_note_cons)) +walk(uint8_t *tag, + int (*visit_addr)(const struct ao_lisp_type *type, void **addr), + int (*visit_poly)(ao_poly *p, uint8_t do_note_cons)) { int i; @@ -193,13 +193,13 @@ walk_all(uint8_t *tag, if (ao_lisp_root[i].type) { void **a = ao_lisp_root[i].addr, *v; if (a && (v = *a)) { - MDBG("root %d\n", MDBG_OFFSET(v)); + MDBG("root ptr %d\n", MDBG_OFFSET(v)); visit_addr(ao_lisp_root[i].type, a); } } else { ao_poly *a = (ao_poly *) ao_lisp_root[i].addr, p; if (a && (p = *a)) { - MDBG("root 0x%04x\n", p); + MDBG("root poly %d\n", MDBG_OFFSET(ao_lisp_ref(p))); visit_poly(a, 0); } } @@ -211,7 +211,7 @@ walk_all(uint8_t *tag, for (i = 0; i < AO_LISP_POOL; i += 4) { if (busy(ao_lisp_cons_last, i)) { void *v = ao_lisp_pool + i; - MDBG("cons %d\n", MDBG_OFFSET(v)); + MDBG("root cons %d\n", MDBG_OFFSET(v)); visit_addr(&ao_lisp_cons_type, &v); } } @@ -221,12 +221,6 @@ walk_all(uint8_t *tag, static void *move_old, *move_new; static int move_size; -static void -move_object(void) -{ - walk_all(ao_lisp_moving, ao_lisp_move, ao_lisp_poly_move); -} - #if MDBG_DUMP static void dump_busy(void) @@ -273,12 +267,6 @@ ao_lisp_poly_mark_ref(ao_poly *p, uint8_t do_note_cons) return ao_lisp_poly_mark(*p, do_note_cons); } -static void -ao_lisp_mark_busy(void) -{ - walk_all(ao_lisp_busy, ao_lisp_mark_ref, ao_lisp_poly_mark_ref); -} - void ao_lisp_collect(void) { @@ -287,7 +275,7 @@ ao_lisp_collect(void) MDBG("collect\n"); /* Mark */ - ao_lisp_mark_busy(); + walk(ao_lisp_busy, ao_lisp_mark_ref, ao_lisp_poly_mark_ref); DUMP_BUSY(); /* Compact */ @@ -300,10 +288,11 @@ ao_lisp_collect(void) while(i < ao_lisp_top) { if (busy(ao_lisp_busy, i)) { MDBG("busy %d -> %d\n", i, top); + MDBG_MOVE_IN(); move_old = &ao_lisp_pool[i]; move_new = &ao_lisp_pool[top]; move_size = 0; - move_object(); + walk(ao_lisp_moving, ao_lisp_move, ao_lisp_poly_move); MDBG("\tbusy size %d\n", move_size); if (move_size == 0) ao_lisp_abort(); @@ -318,6 +307,7 @@ ao_lisp_collect(void) #if MDBG_MOVE DUMP_BUSY(); #endif + MDBG_MOVE_OUT(); } else { i += 4; } @@ -331,9 +321,15 @@ ao_lisp_mark(const struct ao_lisp_type *type, void *addr) { if (!addr) return 1; - if (mark_object(ao_lisp_busy, addr, type->size(addr))) + MDBG_MOVE_IN(); + MDBG_MOVE("mark %d\n", MDBG_OFFSET(addr)); + if (mark_object(ao_lisp_busy, addr, type->size(addr))) { + MDBG_MOVE("already marked\n"); + MDBG_MOVE_OUT(); return 1; + } type->mark(addr); + MDBG_MOVE_OUT(); return 0; } @@ -345,6 +341,7 @@ ao_lisp_poly_mark(ao_poly p, uint8_t do_note_cons) if (!p) return 1; if (type == AO_LISP_CONS && do_note_cons) { + MDBG_MOVE("note cons %d\n", MDBG_OFFSET(ao_lisp_ref(p))); note_cons(ao_lisp_ref(p)); return 0; } else { @@ -371,7 +368,7 @@ void * ao_lisp_move_map(void *addr) { if (addr == move_old) { - if (busy_object(ao_lisp_moving, addr)) + if (move_size != 0) return move_new; } return addr; @@ -382,7 +379,13 @@ check_move(void *addr, int size) { if (addr == move_old) { MDBG_MOVE("mapping %d -> %d\n", MDBG_OFFSET(addr), MDBG_OFFSET(move_new)); - if (!busy_object(ao_lisp_moving, addr)) { + if (move_size && move_size != ((size + 3) & ~3)) + ao_lisp_abort(); + + /* Only copy the object once, otherwise we may + * smash stuff + */ + if (move_size == 0) { MDBG_MOVE(" copy %d\n", size); memmove(move_new, move_old, size); move_size = (size + 3) & ~3; @@ -397,7 +400,7 @@ ao_lisp_move(const struct ao_lisp_type *type, void **ref) { void *addr = *ref; uint8_t *a = addr; - int size = type->size(addr); + int size = type->size(ao_lisp_move_map(addr)); if (!addr) return 1; @@ -462,9 +465,13 @@ ao_lisp_poly_move(ao_poly *ref, uint8_t do_note_cons) type = ao_lisp_poly_base_type(p); addr = ao_lisp_ref(p); + + if ((uint8_t *) addr < ao_lisp_pool || ao_lisp_pool + AO_LISP_POOL <= (uint8_t*) addr) + return 1; + if (type == AO_LISP_CONS && do_note_cons) { - note_cons(addr); addr = check_move(addr, sizeof (struct ao_lisp_cons)); + note_cons(addr); ret = 1; } else { @@ -482,8 +489,8 @@ ao_lisp_poly_move(ao_poly *ref, uint8_t do_note_cons) if (addr != ao_lisp_ref(p)) { ao_poly np = ao_lisp_poly(addr, p & AO_LISP_TYPE_MASK); - MDBG("poly %d moved %04x -> %04x\n", - type, p, np); + MDBG("poly %d moved %d -> %d\n", + type, MDBG_OFFSET(ao_lisp_ref(p)), MDBG_OFFSET(ao_lisp_ref(np))); *ref = np; } return ret; -- cgit v1.2.3 From dba374516ed396633659dec571b6a44b03da8ad1 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 11 Nov 2016 21:16:09 -0800 Subject: altos/lisp: Add save/restore infrastructure. Needs OS support to work. This sticks a few globals past the end of the heap and then asks the OS to save the heap. On restore, the heap is re-populated by the OS and then various global variables reset. Signed-off-by: Keith Packard --- src/lisp/Makefile | 1 + src/lisp/ao_lisp.h | 39 ++++++++++++++++++++++++++--- src/lisp/ao_lisp_builtin.c | 5 ++++ src/lisp/ao_lisp_eval.c | 18 ++++++++++++++ src/lisp/ao_lisp_make_const.c | 2 ++ src/lisp/ao_lisp_save.c | 57 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 src/lisp/ao_lisp_save.c (limited to 'src') diff --git a/src/lisp/Makefile b/src/lisp/Makefile index aa542021..dac11f66 100644 --- a/src/lisp/Makefile +++ b/src/lisp/Makefile @@ -20,6 +20,7 @@ SRCS=\ ao_lisp_lambda.c \ ao_lisp_eval.c \ ao_lisp_rep.c \ + ao_lisp_save.c \ ao_lisp_error.c OBJS=$(SRCS:.c=.o) diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 7a165cd8..44838a34 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -20,6 +20,26 @@ //#include #include +typedef uint16_t ao_poly; +typedef int16_t ao_signed_poly; + +#ifdef AO_LISP_SAVE + +struct ao_lisp_os_save { + ao_poly ao_lisp_atoms; + ao_poly ao_lisp_globals; +}; + +#define AO_LISP_POOL (AO_LISP_POOL_TOTAL - sizeof (struct ao_lisp_os_save)) + +int +ao_lisp_os_save(void); + +int +ao_lisp_os_restore(void); + +#endif + #ifdef AO_LISP_MAKE_CONST #define AO_LISP_POOL_CONST 16384 extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST]; @@ -85,9 +105,6 @@ extern uint16_t ao_lisp_top; extern uint8_t ao_lisp_exception; -typedef uint16_t ao_poly; -typedef int16_t ao_signed_poly; - static inline int ao_lisp_is_const(ao_poly poly) { return poly & AO_LISP_CONST; @@ -228,6 +245,8 @@ enum ao_lisp_builtin_id { builtin_flush, builtin_delay, builtin_led, + builtin_save, + builtin_restore, _builtin_last }; @@ -468,6 +487,12 @@ ao_lisp_poly_move(ao_poly *p, uint8_t note_cons); /* eval */ +void +ao_lisp_eval_clear_globals(void); + +int +ao_lisp_eval_restart(void); + ao_poly ao_lisp_eval(ao_poly p); @@ -542,6 +567,14 @@ ao_lisp_macro(struct ao_lisp_cons *cons); ao_poly ao_lisp_lambda_eval(void); +/* save */ + +ao_poly +ao_lisp_save(struct ao_lisp_cons *cons); + +ao_poly +ao_lisp_restore(struct ao_lisp_cons *cons); + /* error */ void diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index 30631980..ebc69f77 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -82,6 +82,9 @@ static const ao_poly builtin_names[] = { [builtin_flush] = _ao_lisp_atom_flush, [builtin_delay] = _ao_lisp_atom_delay, [builtin_led] = _ao_lisp_atom_led, + [builtin_save] = _ao_lisp_atom_save, + [builtin_restore] = _ao_lisp_atom_restore, + }; static char * @@ -591,5 +594,7 @@ const ao_lisp_func_t ao_lisp_builtins[] = { [builtin_flush] = ao_lisp_flush, [builtin_led] = ao_lisp_led, [builtin_delay] = ao_lisp_delay, + [builtin_save] = ao_lisp_save, + [builtin_restore] = ao_lisp_restore, }; diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index 1c929869..f945bc16 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -546,6 +546,24 @@ static int (*const evals[])(void) = { [eval_while_test] = ao_lisp_eval_while_test, }; +/* + * Called at restore time to reset all execution state + */ + +void +ao_lisp_eval_clear_globals(void) +{ + ao_lisp_stack = NULL; + ao_lisp_frame_current = NULL; + ao_lisp_v = AO_LISP_NIL; +} + +int +ao_lisp_eval_restart(void) +{ + return ao_lisp_stack_push(); +} + ao_poly ao_lisp_eval(ao_poly _v) { diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index 0b3e25a6..0a8c9d07 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -67,6 +67,8 @@ struct builtin_func funcs[] = { "flush", AO_LISP_FUNC_LAMBDA, builtin_flush, "delay", AO_LISP_FUNC_LAMBDA, builtin_delay, "led", AO_LISP_FUNC_LEXPR, builtin_led, + "save", AO_LISP_FUNC_LAMBDA, builtin_save, + "restore", AO_LISP_FUNC_LAMBDA, builtin_restore, }; #define N_FUNC (sizeof funcs / sizeof funcs[0]) diff --git a/src/lisp/ao_lisp_save.c b/src/lisp/ao_lisp_save.c new file mode 100644 index 00000000..2b19fdcb --- /dev/null +++ b/src/lisp/ao_lisp_save.c @@ -0,0 +1,57 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include + +ao_poly +ao_lisp_save(struct ao_lisp_cons *cons) +{ +#ifdef AO_LISP_SAVE + struct ao_lisp_os_save *os = (struct ao_lisp_os_save *) &ao_lisp_pool[AO_LISP_POOL]; + + ao_lisp_collect(); + os->ao_lisp_atoms = ao_lisp_atom_poly(ao_lisp_atoms); + os->ao_lisp_globals = ao_lisp_frame_poly(ao_lisp_frame_global); + if (ao_lisp_os_save()) + return _ao_lisp_atom_t; +#endif + return AO_LISP_NIL; +} + +ao_poly +ao_lisp_restore(struct ao_lisp_cons *cons) +{ +#ifdef AO_LISP_SAVE + struct ao_lisp_os_save *os = (struct ao_lisp_os_save *) &ao_lisp_pool[AO_LISP_POOL]; + + if (ao_lisp_os_restore()) { + + ao_lisp_atoms = ao_lisp_poly_atom(os->ao_lisp_atoms); + ao_lisp_frame_global = ao_lisp_poly_frame(os->ao_lisp_globals); + + /* Clear the eval global variabls */ + ao_lisp_eval_clear_globals(); + + /* Reset the allocator */ + ao_lisp_top = AO_LISP_POOL; + ao_lisp_collect(); + + /* Re-create the evaluator stack */ + if (!ao_lisp_eval_restart()) + return AO_LISP_NIL; + return _ao_lisp_atom_t; + } +#endif + return AO_LISP_NIL; +} -- cgit v1.2.3 From 8f2d60b4c029bffaa559bd1f31f5b15230dfa674 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 11 Nov 2016 21:18:50 -0800 Subject: altos/lisp: Add save/restore to ao_lisp_test Allow testing of the save/restore code under Linux. Signed-off-by: Keith Packard --- src/test/Makefile | 4 ++-- src/test/ao_lisp_os.h | 3 +++ src/test/ao_lisp_test.c | 33 +++++++++++++++++++++++++++++++++ src/test/hanoi.lisp | 2 -- 4 files changed, 38 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/test/Makefile b/src/test/Makefile index d6777090..df24c2b6 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -91,9 +91,9 @@ ao_quaternion_test: ao_quaternion_test.c ao_quaternion.h AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o ao_lisp_cons.o ao_lisp_string.o \ ao_lisp_atom.o ao_lisp_int.o ao_lisp_eval.o ao_lisp_poly.o \ ao_lisp_builtin.o ao_lisp_read.o ao_lisp_rep.o ao_lisp_frame.o \ - ao_lisp_lambda.o ao_lisp_error.o + ao_lisp_lambda.o ao_lisp_error.o ao_lisp_save.o ao_lisp_test: $(AO_LISP_OBJS) cc $(CFLAGS) -o $@ $(AO_LISP_OBJS) -$(AO_LISP_OBJS): ao_lisp.h ao_lisp_const.h +$(AO_LISP_OBJS): ao_lisp.h ao_lisp_const.h ao_lisp_os.h diff --git a/src/test/ao_lisp_os.h b/src/test/ao_lisp_os.h index c979697e..8b9c1475 100644 --- a/src/test/ao_lisp_os.h +++ b/src/test/ao_lisp_os.h @@ -22,6 +22,9 @@ #include #include +#define AO_LISP_POOL_TOTAL 3072 +#define AO_LISP_SAVE + extern int ao_lisp_getc(void); static inline void diff --git a/src/test/ao_lisp_test.c b/src/test/ao_lisp_test.c index 69739100..41dae07a 100644 --- a/src/test/ao_lisp_test.c +++ b/src/test/ao_lisp_test.c @@ -18,6 +18,39 @@ static FILE *ao_lisp_file; static int newline = 1; +static char save_file[] = "lisp.image"; + +int +ao_lisp_os_save(void) +{ + FILE *save = fopen(save_file, "w"); + + if (!save) { + perror(save_file); + return 0; + } + fwrite(ao_lisp_pool, 1, AO_LISP_POOL_TOTAL, save); + fclose(save); + return 1; +} + +int +ao_lisp_os_restore(void) +{ + FILE *restore = fopen(save_file, "r"); + size_t ret; + + if (!restore) { + perror(save_file); + return 0; + } + ret = fread(ao_lisp_pool, 1, AO_LISP_POOL_TOTAL, restore); + fclose(restore); + if (ret != AO_LISP_POOL_TOTAL) + return 0; + return 1; +} + int ao_lisp_getc(void) { diff --git a/src/test/hanoi.lisp b/src/test/hanoi.lisp index 09a3611c..01398d91 100644 --- a/src/test/hanoi.lisp +++ b/src/test/hanoi.lisp @@ -125,5 +125,3 @@ (clear) (_hanoi len 0 1 2) ) - -(hanoi) -- cgit v1.2.3 From 33aeffc123af1f9063969acf585f1caac885ced4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 11 Nov 2016 23:34:54 -0800 Subject: altos/lisp: Append a CRC to the saved image to validate on restore The CRC is actually of the ROM bits, so we can tell if the restored image relates to the currently running code. Signed-off-by: Keith Packard --- src/lambdakey-v1.0/ao_lisp_os_save.c | 53 ++++++++++++++++++++++++++++++++++++ src/lisp/ao_lisp.h | 18 ++++++++---- src/lisp/ao_lisp_make_const.c | 28 +++++++++++++++++++ src/lisp/ao_lisp_mem.c | 2 +- src/lisp/ao_lisp_save.c | 27 +++++++++++++++--- src/test/ao_lisp_test.c | 18 ++++++++++++ src/test/hanoi.lisp | 8 ------ 7 files changed, 136 insertions(+), 18 deletions(-) create mode 100644 src/lambdakey-v1.0/ao_lisp_os_save.c (limited to 'src') diff --git a/src/lambdakey-v1.0/ao_lisp_os_save.c b/src/lambdakey-v1.0/ao_lisp_os_save.c new file mode 100644 index 00000000..44138398 --- /dev/null +++ b/src/lambdakey-v1.0/ao_lisp_os_save.c @@ -0,0 +1,53 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include + +extern uint8_t __flash__[]; + +/* saved variables to rebuild the heap + + ao_lisp_atoms + ao_lisp_frame_global + */ + +int +ao_lisp_os_save(void) +{ + int i; + + for (i = 0; i < AO_LISP_POOL_TOTAL; i += 256) { + uint32_t *dst = (uint32_t *) &__flash__[i]; + uint32_t *src = (uint32_t *) &ao_lisp_pool[i]; + + ao_flash_page(dst, src); + } + return 1; +} + +int +ao_lisp_os_restore_save(struct ao_lisp_os_save *save, int offset) +{ + memcpy(save, &__flash__[offset], sizeof (struct ao_lisp_os_save)); + return 1; +} + +int +ao_lisp_os_restore(void) +{ + memcpy(ao_lisp_pool, __flash__, AO_LISP_POOL_TOTAL); + return 1; +} diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 44838a34..ea3d2a09 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -26,15 +26,21 @@ typedef int16_t ao_signed_poly; #ifdef AO_LISP_SAVE struct ao_lisp_os_save { - ao_poly ao_lisp_atoms; - ao_poly ao_lisp_globals; + ao_poly atoms; + ao_poly globals; + uint16_t const_checksum; + uint16_t const_checksum_inv; }; -#define AO_LISP_POOL (AO_LISP_POOL_TOTAL - sizeof (struct ao_lisp_os_save)) +#define AO_LISP_POOL_EXTRA (sizeof(struct ao_lisp_os_save)) +#define AO_LISP_POOL ((int) (AO_LISP_POOL_TOTAL - AO_LISP_POOL_EXTRA)) int ao_lisp_os_save(void); +int +ao_lisp_os_restore_save(struct ao_lisp_os_save *save, int offset); + int ao_lisp_os_restore(void); @@ -67,12 +73,14 @@ extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST]; #define _ao_lisp_atom_eval _atom("eval") #define _ao_lisp_atom_read _atom("read") #define _ao_lisp_atom_eof _atom("eof") +#define _ao_lisp_atom_save _atom("save") +#define _ao_lisp_atom_restore _atom("restore") #else #include "ao_lisp_const.h" #ifndef AO_LISP_POOL -#define AO_LISP_POOL 16384 +#define AO_LISP_POOL 3072 #endif -extern uint8_t ao_lisp_pool[AO_LISP_POOL]; +extern uint8_t ao_lisp_pool[AO_LISP_POOL + AO_LISP_POOL_EXTRA]; #endif /* Primitive types */ diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index 0a8c9d07..6a29f402 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -86,6 +86,33 @@ is_atom(int offset) return 0; } +#define AO_FEC_CRC_INIT 0xffff + +static inline uint16_t +ao_fec_crc_byte(uint8_t byte, uint16_t crc) +{ + uint8_t bit; + + for (bit = 0; bit < 8; bit++) { + if (((crc & 0x8000) >> 8) ^ (byte & 0x80)) + crc = (crc << 1) ^ 0x8005; + else + crc = (crc << 1); + byte <<= 1; + } + return crc; +} + +uint16_t +ao_fec_crc(const uint8_t *bytes, uint8_t len) +{ + uint16_t crc = AO_FEC_CRC_INIT; + + while (len--) + crc = ao_fec_crc_byte(*bytes++, crc); + return crc; +} + int main(int argc, char **argv) { @@ -126,6 +153,7 @@ main(int argc, char **argv) printf("extern const uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4)));\n"); printf("#define ao_builtin_atoms 0x%04x\n", ao_lisp_atom_poly(ao_lisp_atoms)); printf("#define ao_builtin_frame 0x%04x\n", ao_lisp_frame_poly(ao_lisp_frame_global)); + printf("#define ao_lisp_const_checksum ((uint16_t) 0x%04x)\n", ao_fec_crc(ao_lisp_const, ao_lisp_top)); for (a = ao_lisp_atoms; a; a = ao_lisp_poly_atom(a->next)) { char *n = a->name, c; diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 31ee9e1e..0373f015 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -24,7 +24,7 @@ uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4))); #undef AO_LISP_POOL #define AO_LISP_POOL AO_LISP_POOL_CONST #else -uint8_t ao_lisp_pool[AO_LISP_POOL] __attribute__((aligned(4))); +uint8_t ao_lisp_pool[AO_LISP_POOL + AO_LISP_POOL_EXTRA] __attribute__((aligned(4))); #endif #if 0 diff --git a/src/lisp/ao_lisp_save.c b/src/lisp/ao_lisp_save.c index 2b19fdcb..030846b7 100644 --- a/src/lisp/ao_lisp_save.c +++ b/src/lisp/ao_lisp_save.c @@ -17,12 +17,18 @@ ao_poly ao_lisp_save(struct ao_lisp_cons *cons) { + if (!ao_lisp_check_argc(_ao_lisp_atom_save, cons, 0, 0)) + return AO_LISP_NIL; + #ifdef AO_LISP_SAVE struct ao_lisp_os_save *os = (struct ao_lisp_os_save *) &ao_lisp_pool[AO_LISP_POOL]; ao_lisp_collect(); - os->ao_lisp_atoms = ao_lisp_atom_poly(ao_lisp_atoms); - os->ao_lisp_globals = ao_lisp_frame_poly(ao_lisp_frame_global); + os->atoms = ao_lisp_atom_poly(ao_lisp_atoms); + os->globals = ao_lisp_frame_poly(ao_lisp_frame_global); + os->const_checksum = ao_lisp_const_checksum; + os->const_checksum_inv = ~ao_lisp_const_checksum; + if (ao_lisp_os_save()) return _ao_lisp_atom_t; #endif @@ -32,13 +38,26 @@ ao_lisp_save(struct ao_lisp_cons *cons) ao_poly ao_lisp_restore(struct ao_lisp_cons *cons) { + if (!ao_lisp_check_argc(_ao_lisp_atom_save, cons, 0, 0)) + return AO_LISP_NIL; + #ifdef AO_LISP_SAVE + struct ao_lisp_os_save save; struct ao_lisp_os_save *os = (struct ao_lisp_os_save *) &ao_lisp_pool[AO_LISP_POOL]; + if (!ao_lisp_os_restore_save(&save, AO_LISP_POOL)) + return ao_lisp_error(AO_LISP_INVALID, "header restore failed"); + + if (save.const_checksum != ao_lisp_const_checksum || + save.const_checksum_inv != (uint16_t) ~ao_lisp_const_checksum) + { + return ao_lisp_error(AO_LISP_INVALID, "image is corrupted or stale"); + } + if (ao_lisp_os_restore()) { - ao_lisp_atoms = ao_lisp_poly_atom(os->ao_lisp_atoms); - ao_lisp_frame_global = ao_lisp_poly_frame(os->ao_lisp_globals); + ao_lisp_atoms = ao_lisp_poly_atom(os->atoms); + ao_lisp_frame_global = ao_lisp_poly_frame(os->globals); /* Clear the eval global variabls */ ao_lisp_eval_clear_globals(); diff --git a/src/test/ao_lisp_test.c b/src/test/ao_lisp_test.c index 41dae07a..648d1abe 100644 --- a/src/test/ao_lisp_test.c +++ b/src/test/ao_lisp_test.c @@ -34,6 +34,24 @@ ao_lisp_os_save(void) return 1; } +int +ao_lisp_os_restore_save(struct ao_lisp_os_save *save, int offset) +{ + FILE *restore = fopen(save_file, "r"); + size_t ret; + + if (!restore) { + perror(save_file); + return 0; + } + fseek(restore, offset, SEEK_SET); + ret = fread(save, sizeof (struct ao_lisp_os_save), 1, restore); + fclose(restore); + if (ret != 1) + return 0; + return 1; +} + int ao_lisp_os_restore(void) { diff --git a/src/test/hanoi.lisp b/src/test/hanoi.lisp index 01398d91..2b614829 100644 --- a/src/test/hanoi.lisp +++ b/src/test/hanoi.lisp @@ -6,19 +6,11 @@ (patom "\033[2J" nil) ) -(defun test () - (clear) - (move-to 30 12) - (patom "hello, world") - (move-to 0 19) - ) - (setq stack '("*" "**" "***" "****" "*****" "******" "*******")) (setq stacks nil) (defun display-string (x y str) - (move-to x y) (move-to x y) (patom str) ) -- cgit v1.2.3 From 30db58ade19ec69272a8c39c2f13d7919ca491a9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 11 Nov 2016 23:36:22 -0800 Subject: altos/lambdakey: Get save/restore working Need the HSI clock running for the flash hardware to work. Signed-off-by: Keith Packard --- src/lambdakey-v1.0/Makefile | 7 ++- src/lambdakey-v1.0/ao_pins.h | 6 ++- src/lambdakey-v1.0/lambda.ld | 117 +++++++++++++++++++++++++++++++++++++++++++ src/stmf0/ao_flash_stm.c | 7 +-- 4 files changed, 128 insertions(+), 9 deletions(-) create mode 100644 src/lambdakey-v1.0/lambda.ld (limited to 'src') diff --git a/src/lambdakey-v1.0/Makefile b/src/lambdakey-v1.0/Makefile index 1ac04f24..c71e1ab5 100644 --- a/src/lambdakey-v1.0/Makefile +++ b/src/lambdakey-v1.0/Makefile @@ -34,6 +34,7 @@ ALTOS_SRC = \ ao_mutex.c \ ao_usb_stm.c \ ao_serial_stm.c \ + ao_flash_stm.c \ ao_lisp_lex.c \ ao_lisp_mem.c \ ao_lisp_cons.c \ @@ -41,20 +42,22 @@ ALTOS_SRC = \ ao_lisp_string.c \ ao_lisp_atom.c \ ao_lisp_int.c \ - ao_lisp_prim.c \ + ao_lisp_poly.c \ ao_lisp_builtin.c \ ao_lisp_read.c \ ao_lisp_rep.c \ ao_lisp_frame.c \ ao_lisp_error.c \ ao_lisp_lambda.c \ + ao_lisp_save.c \ + ao_lisp_os_save.c \ ao_exti_stm.c PRODUCT=LambdaKey-v1.0 PRODUCT_DEF=-DLAMBDAKEY IDPRODUCT=0x000a -CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -Os -g +CFLAGS = $(PRODUCT_DEF) -I. $(STMF0_CFLAGS) -Os -g LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Tlambda.ld diff --git a/src/lambdakey-v1.0/ao_pins.h b/src/lambdakey-v1.0/ao_pins.h index b8429c55..167d0857 100644 --- a/src/lambdakey-v1.0/ao_pins.h +++ b/src/lambdakey-v1.0/ao_pins.h @@ -25,9 +25,13 @@ #define AO_LED_RED (1 << LED_PIN_RED) #define AO_LED_PANIC AO_LED_RED #define AO_CMD_LEN 128 -#define AO_LISP_POOL 3072 +#define AO_LISP_POOL_TOTAL 3072 +#define AO_LISP_SAVE 1 #define AO_STACK_SIZE 1024 +/* need HSI active to write to flash */ +#define AO_NEED_HSI 1 + #define LEDS_AVAILABLE (AO_LED_RED) #define AO_POWER_MANAGEMENT 0 diff --git a/src/lambdakey-v1.0/lambda.ld b/src/lambdakey-v1.0/lambda.ld new file mode 100644 index 00000000..5de65eb5 --- /dev/null +++ b/src/lambdakey-v1.0/lambda.ld @@ -0,0 +1,117 @@ +/* + * Copyright © 2012 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +MEMORY { + rom (rx) : ORIGIN = 0x08001000, LENGTH = 25K + flash (r): ORIGIN = 0x08007400, LENGTH = 3k + ram (!w) : ORIGIN = 0x20000000, LENGTH = 6k - 128 + stack (!w) : ORIGIN = 0x20000000 + 6k - 128, LENGTH = 128 +} + +INCLUDE registers.ld + +EXTERN (stm_interrupt_vector) + +SECTIONS { + /* + * Rom contents + */ + + .interrupt ORIGIN(ram) : AT (ORIGIN(rom)) { + __interrupt_start__ = .; + __interrupt_rom__ = ORIGIN(rom); + *(.interrupt) /* Interrupt vectors */ + __interrupt_end__ = .; + } > ram + + .text ORIGIN(rom) + 0x100 : { + __text_start__ = .; + + /* Ick. What I want is to specify the + * addresses of some global constants so + * that I can find them across versions + * of the application. I can't figure out + * how to make gnu ld do that, so instead + * we just load the two files that include + * these defines in the right order here and + * expect things to 'just work'. Don't change + * the contents of those files, ok? + */ + ao_romconfig.o(.romconfig*) + ao_product.o(.romconfig*) + + *(.text*) /* Executable code */ + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.rodata*) /* Constants */ + + } > rom + __text_end__ = .; + + + /* Boot data which must live at the start of ram so that + * the application and bootloader share the same addresses. + * This must be all uninitialized data + */ + .boot (NOLOAD) : { + __boot_start__ = .; + *(.boot) + . = ALIGN(4); + __boot_end__ = .; + } >ram + + /* Functions placed in RAM (required for flashing) + * + * Align to 8 bytes as that's what the ARM likes text + * segment alignments to be, and if we don't, then + * we end up with a mismatch between the location in + * ROM and the desired location in RAM. I don't + * entirely understand this, but at least this appears + * to work... + */ + + .textram BLOCK(8): { + __data_start__ = .; + __text_ram_start__ = .; + *(.ramtext) + __text_ram_end = .; + } >ram AT>rom + + /* Data -- relocated to RAM, but written to ROM + */ + .data : { + *(.data) /* initialized data */ + . = ALIGN(4); + __data_end__ = .; + } >ram AT>rom + + .bss : { + __bss_start__ = .; + *(.bss) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } >ram + + PROVIDE(end = .); + + PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack)); + + __flash__ = ORIGIN(flash); +} + +ENTRY(start); diff --git a/src/stmf0/ao_flash_stm.c b/src/stmf0/ao_flash_stm.c index 2aeff388..ef2e2619 100644 --- a/src/stmf0/ao_flash_stm.c +++ b/src/stmf0/ao_flash_stm.c @@ -44,12 +44,7 @@ ao_flash_lock(void) stm_flash.cr |= (1 << STM_FLASH_CR_LOCK); } -static void -ao_flash_wait_bsy(void) -{ - while (stm_flash.sr & (1 << STM_FLASH_SR_BSY)) - ; -} +#define ao_flash_wait_bsy() do { while (stm_flash.sr & (1 << STM_FLASH_SR_BSY)); } while (0) static void __attribute__ ((section(".ramtext"),noinline)) _ao_flash_erase_page(uint32_t *page) -- cgit v1.2.3 From affcf6ffc08313151541993ee543bfe390165e81 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 11 Nov 2016 23:38:03 -0800 Subject: altos/stmf0: Add a comment about the requirements for using ao_flash_stm Need HSI clock and the flashing functions loaded in ram. Signed-off-by: Keith Packard --- src/stmf0/ao_flash_stm.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/stmf0/ao_flash_stm.c b/src/stmf0/ao_flash_stm.c index ef2e2619..2d57eea7 100644 --- a/src/stmf0/ao_flash_stm.c +++ b/src/stmf0/ao_flash_stm.c @@ -19,6 +19,12 @@ #include #include +/* Note that the HSI clock must be running for this code to work. + * Also, special care must be taken with the linker to ensure that the + * functions marked 'ramtext' land in ram and not rom. An example of that + * can be found in altos-loader.ld + */ + static uint8_t ao_flash_is_locked(void) { -- cgit v1.2.3 From ddb4b8d90478ae324aa207a7541352c1ac9451ee Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 14 Nov 2016 18:45:12 -0800 Subject: altos/lisp: Change GC to do moves in batches of 32 This should make it quite a bit faster than doing one at a time. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 69 ++++- src/lisp/ao_lisp_atom.c | 14 +- src/lisp/ao_lisp_cons.c | 32 +- src/lisp/ao_lisp_eval.c | 21 +- src/lisp/ao_lisp_frame.c | 48 +-- src/lisp/ao_lisp_lambda.c | 3 + src/lisp/ao_lisp_mem.c | 745 ++++++++++++++++++++++++++++++++-------------- src/lisp/ao_lisp_read.c | 64 ++-- src/lisp/ao_lisp_string.c | 33 +- 9 files changed, 674 insertions(+), 355 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index ea3d2a09..906bae19 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -134,6 +134,7 @@ struct ao_lisp_type { int (*size)(void *addr); void (*mark)(void *addr); void (*move)(void *addr); + char name[]; }; struct ao_lisp_cons { @@ -304,11 +305,17 @@ ao_lisp_other_poly(const void *other) } static inline int -ao_lisp_mem_round(int size) +ao_lisp_size_round(int size) { return (size + 3) & ~3; } +static inline int +ao_lisp_size(const struct ao_lisp_type *type, void *addr) +{ + return ao_lisp_size_round(type->size(addr)); +} + #define AO_LISP_OTHER_POLY(other) ((ao_poly)(other) + AO_LISP_OTHER) static inline int ao_lisp_poly_base_type(ao_poly poly) { @@ -389,7 +396,7 @@ ao_lisp_mark(const struct ao_lisp_type *type, void *addr); /* returns 1 if the object was already marked */ int -ao_lisp_mark_memory(void *addr, int size); +ao_lisp_mark_memory(const struct ao_lisp_type *type, void *addr); void * ao_lisp_move_map(void *addr); @@ -400,7 +407,7 @@ ao_lisp_move(const struct ao_lisp_type *type, void **ref); /* returns 1 if the object was already moved */ int -ao_lisp_move_memory(void **ref, int size); +ao_lisp_move_memory(const struct ao_lisp_type *type, void **ref); void * ao_lisp_alloc(int size); @@ -408,14 +415,23 @@ ao_lisp_alloc(int size); void ao_lisp_collect(void); -int -ao_lisp_root_add(const struct ao_lisp_type *type, void *addr); +void +ao_lisp_cons_stash(int id, struct ao_lisp_cons *cons); -int -ao_lisp_root_poly_add(ao_poly *p); +struct ao_lisp_cons * +ao_lisp_cons_fetch(int id); void -ao_lisp_root_clear(void *addr); +ao_lisp_string_stash(int id, char *string); + +char * +ao_lisp_string_fetch(int id); + +void +ao_lisp_poly_stash(int id, ao_poly poly); + +ao_poly +ao_lisp_poly_fetch(int id); /* cons */ extern const struct ao_lisp_type ao_lisp_cons_type; @@ -435,9 +451,6 @@ ao_lisp_cons_length(struct ao_lisp_cons *cons); /* string */ extern const struct ao_lisp_type ao_lisp_string_type; -char * -ao_lisp_string_new(int len); - char * ao_lisp_string_copy(char *a); @@ -529,6 +542,10 @@ char * ao_lisp_args_name(uint8_t args); /* read */ +extern struct ao_lisp_cons *ao_lisp_read_cons; +extern struct ao_lisp_cons *ao_lisp_read_cons_tail; +extern struct ao_lisp_cons *ao_lisp_read_stack; + ao_poly ao_lisp_read(void); @@ -585,6 +602,8 @@ ao_lisp_restore(struct ao_lisp_cons *cons); /* error */ +extern const struct ao_lisp_type ao_lisp_stack_type; + void ao_lisp_stack_print(void); @@ -631,4 +650,32 @@ ao_lisp_frames_dump(void) #define DBG_FRAMES() #endif +#define DBG_MEM 1 +#define DBG_MEM_START 1 + +#if DBG_MEM + +#include +extern int dbg_move_depth; +#define MDBG_DUMP 1 +#define MDBG_OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_pool)) + +extern int dbg_mem; + +#define MDBG_DO(a) a +#define MDBG_MOVE(...) do { if (dbg_mem) { int d; for (d = 0; d < dbg_move_depth; d++) printf (" "); printf(__VA_ARGS__); } } while (0) +#define MDBG_MORE(...) do { if (dbg_mem) printf(__VA_ARGS__); } while (0) +#define MDBG_MOVE_IN() (dbg_move_depth++) +#define MDBG_MOVE_OUT() (assert(--dbg_move_depth >= 0)) + +#else + +#define MDBG_DO(a) +#define MDBG_MOVE(...) +#define MDBG_MORE(...) +#define MDBG_MOVE_IN() +#define MDBG_MOVE_OUT() + +#endif + #endif /* _AO_LISP_H_ */ diff --git a/src/lisp/ao_lisp_atom.c b/src/lisp/ao_lisp_atom.c index e1d9b082..6705f140 100644 --- a/src/lisp/ao_lisp_atom.c +++ b/src/lisp/ao_lisp_atom.c @@ -38,7 +38,7 @@ static void atom_mark(void *addr) atom = ao_lisp_poly_atom(atom->next); if (!atom) break; - if (ao_lisp_mark_memory(atom, atom_size(atom))) + if (ao_lisp_mark_memory(&ao_lisp_atom_type, atom)) break; } } @@ -53,7 +53,7 @@ static void atom_move(void *addr) if (!next) break; - ret = ao_lisp_move_memory((void **) &next, atom_size(next)); + ret = ao_lisp_move_memory(&ao_lisp_atom_type, (void **) &next); if (next != ao_lisp_poly_atom(atom->next)) atom->next = ao_lisp_atom_poly(next); if (ret) @@ -66,6 +66,7 @@ const struct ao_lisp_type ao_lisp_atom_type = { .mark = atom_mark, .size = atom_size, .move = atom_move, + .name = "atom" }; struct ao_lisp_atom *ao_lisp_atoms; @@ -85,12 +86,12 @@ ao_lisp_atom_intern(char *name) return atom; } #endif + ao_lisp_string_stash(0, name); atom = ao_lisp_alloc(name_size(name)); + name = ao_lisp_string_fetch(0); if (atom) { atom->type = AO_LISP_ATOM; atom->next = ao_lisp_atom_poly(ao_lisp_atoms); - if (!ao_lisp_atoms) - ao_lisp_root_add(&ao_lisp_atom_type, &ao_lisp_atoms); ao_lisp_atoms = atom; strcpy(atom->name, name); } @@ -103,11 +104,8 @@ struct ao_lisp_frame *ao_lisp_frame_current; static void ao_lisp_atom_init(void) { - if (!ao_lisp_frame_global) { + if (!ao_lisp_frame_global) ao_lisp_frame_global = ao_lisp_frame_new(0); - ao_lisp_root_add(&ao_lisp_frame_type, &ao_lisp_frame_global); - ao_lisp_root_add(&ao_lisp_frame_type, &ao_lisp_frame_current); - } } static ao_poly * diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c index c7d8382f..311d63ab 100644 --- a/src/lisp/ao_lisp_cons.c +++ b/src/lisp/ao_lisp_cons.c @@ -14,8 +14,6 @@ #include "ao_lisp.h" -#define OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_const)) - static void cons_mark(void *addr) { struct ao_lisp_cons *cons = addr; @@ -25,7 +23,7 @@ static void cons_mark(void *addr) cons = ao_lisp_poly_cons(cons->cdr); if (!cons) break; - if (ao_lisp_mark_memory(cons, sizeof (struct ao_lisp_cons))) + if (ao_lisp_mark_memory(&ao_lisp_cons_type, cons)) break; } } @@ -47,13 +45,17 @@ static void cons_move(void *addr) struct ao_lisp_cons *cdr; int ret; + MDBG_MOVE("cons_move start %d (%d, %d)\n", + MDBG_OFFSET(cons), MDBG_OFFSET(ao_lisp_ref(cons->car)), MDBG_OFFSET(ao_lisp_ref(cons->cdr))); (void) ao_lisp_poly_move(&cons->car, 1); cdr = ao_lisp_poly_cons(cons->cdr); if (!cdr) break; - ret = ao_lisp_move_memory((void **) &cdr, sizeof (struct ao_lisp_cons)); + ret = ao_lisp_move_memory(&ao_lisp_cons_type, (void **) &cdr); if (cdr != ao_lisp_poly_cons(cons->cdr)) cons->cdr = ao_lisp_cons_poly(cdr); + MDBG_MOVE("cons_move end %d (%d, %d)\n", + MDBG_OFFSET(cons), MDBG_OFFSET(ao_lisp_ref(cons->car)), MDBG_OFFSET(ao_lisp_ref(cons->cdr))); if (ret) break; cons = cdr; @@ -64,31 +66,23 @@ const struct ao_lisp_type ao_lisp_cons_type = { .mark = cons_mark, .size = cons_size, .move = cons_move, + .name = "cons", }; -static ao_poly cons_car; -static struct ao_lisp_cons *cons_cdr; -static int been_here; - struct ao_lisp_cons * ao_lisp_cons_cons(ao_poly car, struct ao_lisp_cons *cdr) { struct ao_lisp_cons *cons; - if (!been_here) { - ao_lisp_root_add(&ao_lisp_cons_type, &cons_cdr); - ao_lisp_root_poly_add(&cons_car); - been_here = 1; - } - cons_car = car; - cons_cdr = cdr; + ao_lisp_poly_stash(0, car); + ao_lisp_cons_stash(0, cdr); cons = ao_lisp_alloc(sizeof (struct ao_lisp_cons)); + car = ao_lisp_poly_fetch(0); + cdr = ao_lisp_cons_fetch(0); if (!cons) return NULL; - cons->car = cons_car; - cons->cdr = ao_lisp_cons_poly(cons_cdr); - cons_car = AO_LISP_NIL; - cons_cdr = NULL; + cons->car = car; + cons->cdr = ao_lisp_cons_poly(cdr); return cons; } diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index f945bc16..04d0e70a 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -16,6 +16,8 @@ #include "ao_lisp.h" #include +const struct ao_lisp_type ao_lisp_stack_type; + static int stack_size(void *addr) { @@ -34,13 +36,11 @@ stack_mark(void *addr) ao_lisp_poly_mark(stack->frame, 0); ao_lisp_poly_mark(stack->list, 0); stack = ao_lisp_poly_stack(stack->prev); - if (ao_lisp_mark_memory(stack, sizeof (struct ao_lisp_stack))) + if (ao_lisp_mark_memory(&ao_lisp_stack_type, stack)) break; } } -static const struct ao_lisp_type ao_lisp_stack_type; - static void stack_move(void *addr) { @@ -57,8 +57,7 @@ stack_move(void *addr) prev = ao_lisp_poly_stack(stack->prev); if (!prev) break; - ret = ao_lisp_move_memory((void **) &prev, - sizeof (struct ao_lisp_stack)); + ret = ao_lisp_move_memory(&ao_lisp_stack_type, (void **) &prev); if (prev != ao_lisp_poly_stack(stack->prev)) stack->prev = ao_lisp_stack_poly(prev); if (ret) @@ -67,10 +66,11 @@ stack_move(void *addr) } } -static const struct ao_lisp_type ao_lisp_stack_type = { +const struct ao_lisp_type ao_lisp_stack_type = { .size = stack_size, .mark = stack_mark, - .move = stack_move + .move = stack_move, + .name = "stack" }; struct ao_lisp_stack *ao_lisp_stack; @@ -567,14 +567,7 @@ ao_lisp_eval_restart(void) ao_poly ao_lisp_eval(ao_poly _v) { - static uint8_t been_here; - ao_lisp_v = _v; - if (!been_here) { - been_here = 1; - ao_lisp_root_add(&ao_lisp_stack_type, &ao_lisp_stack); - ao_lisp_root_poly_add(&ao_lisp_v); - } if (!ao_lisp_stack_push()) return AO_LISP_NIL; diff --git a/src/lisp/ao_lisp_frame.c b/src/lisp/ao_lisp_frame.c index 082860ee..e23a6413 100644 --- a/src/lisp/ao_lisp_frame.c +++ b/src/lisp/ao_lisp_frame.c @@ -14,12 +14,6 @@ #include "ao_lisp.h" -#if 0 -#define DBG(...) printf(__VA_ARGS__) -#else -#define DBG(...) -#endif - static inline int frame_num_size(int num) { @@ -33,8 +27,6 @@ frame_size(void *addr) return frame_num_size(frame->num); } -#define OFFSET(a) ((int) ((uint8_t *) (ao_lisp_ref(a)) - ao_lisp_const)) - static void frame_mark(void *addr) { @@ -42,22 +34,23 @@ frame_mark(void *addr) int f; for (;;) { - DBG("frame mark %p\n", frame); + MDBG_MOVE("frame mark %d\n", MDBG_OFFSET(frame)); if (!AO_LISP_IS_POOL(frame)) break; for (f = 0; f < frame->num; f++) { struct ao_lisp_val *v = &frame->vals[f]; ao_lisp_poly_mark(v->val, 0); - DBG ("\tframe mark atom %s %d val %d at %d\n", - ao_lisp_poly_atom(v->atom)->name, - OFFSET(v->atom), OFFSET(v->val), f); + MDBG_MOVE("frame mark atom %s %d val %d at %d\n", + ao_lisp_poly_atom(v->atom)->name, + MDBG_OFFSET(ao_lisp_ref(v->atom)), + MDBG_OFFSET(ao_lisp_ref(v->val)), f); } frame = ao_lisp_poly_frame(frame->next); - DBG("frame next %p\n", frame); + MDBG_MOVE("frame next %d\n", MDBG_OFFSET(frame)); if (!frame) break; - if (ao_lisp_mark_memory(frame, frame_size(frame))) + if (ao_lisp_mark_memory(&ao_lisp_frame_type, frame)) break; } } @@ -72,22 +65,29 @@ frame_move(void *addr) struct ao_lisp_frame *next; int ret; - DBG("frame move %p\n", frame); + MDBG_MOVE("frame move %d\n", MDBG_OFFSET(frame)); if (!AO_LISP_IS_POOL(frame)) break; for (f = 0; f < frame->num; f++) { struct ao_lisp_val *v = &frame->vals[f]; ao_lisp_poly_move(&v->atom, 0); - DBG("moved atom %s\n", ao_lisp_poly_atom(v->atom)->name); ao_lisp_poly_move(&v->val, 0); + MDBG_MOVE("frame move atom %s %d val %d at %d\n", + ao_lisp_poly_atom(v->atom)->name, + MDBG_OFFSET(ao_lisp_ref(v->atom)), + MDBG_OFFSET(ao_lisp_ref(v->val)), f); } next = ao_lisp_poly_frame(frame->next); if (!next) break; - ret = ao_lisp_move_memory((void **) &next, frame_size(next)); - if (next != ao_lisp_poly_frame(frame->next)) + ret = ao_lisp_move_memory(&ao_lisp_frame_type, (void **) &next); + if (next != ao_lisp_poly_frame(frame->next)) { + MDBG_MOVE("frame next moved from %d to %d\n", + MDBG_OFFSET(ao_lisp_poly_frame(frame->next)), + MDBG_OFFSET(next)); frame->next = ao_lisp_frame_poly(next); + } if (ret) break; frame = next; @@ -97,7 +97,8 @@ frame_move(void *addr) const struct ao_lisp_type ao_lisp_frame_type = { .mark = frame_mark, .size = frame_size, - .move = frame_move + .move = frame_move, + .name = "frame", }; void @@ -206,8 +207,8 @@ ao_lisp_frame_add(struct ao_lisp_frame **frame_ref, ao_poly atom, ao_poly val) if (!ref) { int f; - ao_lisp_root_poly_add(&atom); - ao_lisp_root_poly_add(&val); + ao_lisp_poly_stash(0, atom); + ao_lisp_poly_stash(1, val); if (frame) { f = frame->num; frame = ao_lisp_frame_realloc(frame_ref, f + 1); @@ -215,12 +216,11 @@ ao_lisp_frame_add(struct ao_lisp_frame **frame_ref, ao_poly atom, ao_poly val) f = 0; frame = ao_lisp_frame_new(1); } - ao_lisp_root_clear(&atom); - ao_lisp_root_clear(&val); + atom = ao_lisp_poly_fetch(0); + val = ao_lisp_poly_fetch(1); if (!frame) return 0; *frame_ref = frame; - DBG ("add atom %s %d, val %d at %d\n", ao_lisp_poly_atom(atom)->name, OFFSET(atom), OFFSET(val), f); frame->vals[f].atom = atom; ref = &frame->vals[f].val; } diff --git a/src/lisp/ao_lisp_lambda.c b/src/lisp/ao_lisp_lambda.c index c53a38fd..6020a8b8 100644 --- a/src/lisp/ao_lisp_lambda.c +++ b/src/lisp/ao_lisp_lambda.c @@ -47,6 +47,7 @@ const struct ao_lisp_type ao_lisp_lambda_type = { .size = lambda_size, .mark = lambda_mark, .move = lambda_move, + .name = "lambda", }; void @@ -68,7 +69,9 @@ ao_lisp_lambda_print(ao_poly poly) ao_poly ao_lisp_lambda_alloc(struct ao_lisp_cons *code, int args) { + ao_lisp_cons_stash(0, code); struct ao_lisp_lambda *lambda = ao_lisp_alloc(sizeof (struct ao_lisp_lambda)); + code = ao_lisp_cons_fetch(0); struct ao_lisp_cons *arg; int f; diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 0373f015..60f4bbee 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -18,64 +18,243 @@ #include #ifdef AO_LISP_MAKE_CONST + +/* + * When building the constant table, it is the + * pool for allocations. + */ + #include uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4))); #define ao_lisp_pool ao_lisp_const #undef AO_LISP_POOL #define AO_LISP_POOL AO_LISP_POOL_CONST + #else + uint8_t ao_lisp_pool[AO_LISP_POOL + AO_LISP_POOL_EXTRA] __attribute__((aligned(4))); -#endif -#if 0 -#define MDBG_COLLECT_ALWAYS #endif #if 0 #define MDBG_POOL #endif -#if 0 -#include -#define MDBG_INCLUDE -#if 1 -#define MDBG_MOVE(...) do { int d; for (d = 0; d < move_depth; d++) printf (" "); printf(__VA_ARGS__); } while (0) -#endif -#define MDBG_OFFSET(a) ((int) ((uint8_t *) (a) - ao_lisp_pool)) -#define MDBG(...) printf(__VA_ARGS__) -#define MDBG_DO(a) a -static int move_depth; -#define MDBG_MOVE_IN() (move_depth++) -#define MDBG_MOVE_OUT() (assert(--move_depth >= 0)) +#if DBG_MEM +int dbg_move_depth; +int dbg_mem = DBG_MEM_START; +int dbg_collects = 0; +int dbg_validate = 0; + +struct ao_lisp_record { + struct ao_lisp_record *next; + const struct ao_lisp_type *type; + void *addr; + int size; +}; + +static struct ao_lisp_record *record_head, **record_tail; + +static void +ao_lisp_record_free(struct ao_lisp_record *record) +{ + while (record) { + struct ao_lisp_record *next = record->next; + free(record); + record = next; + } +} + +static void +ao_lisp_record_reset(void) +{ + ao_lisp_record_free(record_head); + record_head = NULL; + record_tail = &record_head; +} + +static void +ao_lisp_record(const struct ao_lisp_type *type, + void *addr, + int size) +{ + struct ao_lisp_record *r = malloc(sizeof (struct ao_lisp_record)); + + r->next = NULL; + r->type = type; + r->addr = addr; + r->size = size; + *record_tail = r; + record_tail = &r->next; +} + +static struct ao_lisp_record * +ao_lisp_record_save(void) +{ + struct ao_lisp_record *r = record_head; + + record_head = NULL; + record_tail = &record_head; + return r; +} + +static void +ao_lisp_record_compare(char *where, + struct ao_lisp_record *a, + struct ao_lisp_record *b) +{ + while (a && b) { + if (a->type != b->type || a->size != b->size) { + printf("%s record difers %d %s %d -> %d %s %d\n", + where, + MDBG_OFFSET(a->addr), + a->type->name, + a->size, + MDBG_OFFSET(b->addr), + b->type->name, + b->size); + ao_lisp_abort(); + } + a = a->next; + b = b->next; + } + if (a) { + printf("%s record differs %d %s %d -> NULL\n", + where, + MDBG_OFFSET(a->addr), + a->type->name, + a->size); + ao_lisp_abort(); + } + if (b) { + printf("%s record differs NULL -> %d %s %d\n", + where, + MDBG_OFFSET(b->addr), + b->type->name, + b->size); + ao_lisp_abort(); + } +} + #else -#define MDBG(...) -#define MDBG_DO(a) -#define MDBG_MOVE(...) -#define MDBG_MOVE_IN() -#define MDBG_MOVE_OUT() +#define ao_lisp_record_reset() #endif uint8_t ao_lisp_exception; struct ao_lisp_root { - void **addr; const struct ao_lisp_type *type; + void **addr; }; -#define AO_LISP_ROOT 16 +static struct ao_lisp_cons *save_cons[2]; +static char *save_string[2]; +static ao_poly save_poly[2]; + +static const struct ao_lisp_root ao_lisp_root[] = { + { + .type = &ao_lisp_cons_type, + .addr = (void **) &save_cons[0], + }, + { + .type = &ao_lisp_cons_type, + .addr = (void **) &save_cons[1], + }, + { + .type = &ao_lisp_string_type, + .addr = (void **) &save_string[0] + }, + { + .type = &ao_lisp_string_type, + .addr = (void **) &save_string[1] + }, + { + .type = NULL, + .addr = (void **) &save_poly[0] + }, + { + .type = NULL, + .addr = (void **) &save_poly[1] + }, + { + .type = &ao_lisp_atom_type, + .addr = (void **) &ao_lisp_atoms + }, + { + .type = &ao_lisp_frame_type, + .addr = (void **) &ao_lisp_frame_global, + }, + { + .type = &ao_lisp_frame_type, + .addr = (void **) &ao_lisp_frame_current, + }, + { + .type = &ao_lisp_stack_type, + .addr = (void **) &ao_lisp_stack, + }, + { + .type = NULL, + .addr = (void **) &ao_lisp_v, + }, + { + .type = &ao_lisp_cons_type, + .addr = (void **) &ao_lisp_read_cons, + }, + { + .type = &ao_lisp_cons_type, + .addr = (void **) &ao_lisp_read_cons_tail, + }, + { + .type = &ao_lisp_cons_type, + .addr = (void **) &ao_lisp_read_stack, + }, +}; -static struct ao_lisp_root ao_lisp_root[AO_LISP_ROOT]; +#define AO_LISP_ROOT (sizeof (ao_lisp_root) / sizeof (ao_lisp_root[0])) #define AO_LISP_BUSY_SIZE ((AO_LISP_POOL + 31) / 32) static uint8_t ao_lisp_busy[AO_LISP_BUSY_SIZE]; -static uint8_t ao_lisp_moving[AO_LISP_BUSY_SIZE]; static uint8_t ao_lisp_cons_note[AO_LISP_BUSY_SIZE]; static uint8_t ao_lisp_cons_last[AO_LISP_BUSY_SIZE]; static uint8_t ao_lisp_cons_noted; uint16_t ao_lisp_top; +struct ao_lisp_chunk { + uint16_t old_addr; + union { + uint16_t size; + uint16_t new_addr; + }; +}; + +#define AO_LISP_NCHUNK 32 + +static struct ao_lisp_chunk ao_lisp_chunk[AO_LISP_NCHUNK]; + +/* Offset of an address within the pool. */ +static inline uint16_t pool_offset(void *addr) { + if (!AO_LISP_IS_POOL(addr)) + ao_lisp_abort(); + return ((uint8_t *) addr) - ao_lisp_pool; +} + +/* + * Convert back and forth between 'poly's used + * as short addresses in the pool and addresses. + * These are used in the chunk code. + */ +static inline ao_poly pool_poly(void *addr) { + if (!AO_LISP_IS_POOL(addr)) + ao_lisp_abort(); + return ((uint8_t *) addr) - AO_LISP_POOL_BASE; +} + +static inline void *pool_ref(ao_poly p) { + return AO_LISP_POOL_BASE + p; +} + static inline void mark(uint8_t *tag, int offset) { int byte = offset >> 5; int bit = (offset >> 2) & 7; @@ -101,24 +280,28 @@ static inline int limit(int offset) { return min(AO_LISP_POOL, max(offset, 0)); } +static int total_marked; + +/* + * Mark a range of addresses + */ static int mark_object(uint8_t *tag, void *addr, int size) { int base; int bound; - if (!addr) - return 1; + MDBG_DO(if (!AO_LISP_IS_POOL((uint8_t *) addr + size - 1)) + ao_lisp_abort()); - if ((uint8_t *) addr < ao_lisp_pool || ao_lisp_pool + AO_LISP_POOL <= (uint8_t*) addr) - return 1; - - base = (uint8_t *) addr - ao_lisp_pool; + base = pool_offset(addr); bound = base + size; - base = limit(base); - bound = limit(bound); + MDBG_DO(if (bound > ao_lisp_top) ao_lisp_abort()); + if (busy(tag, base)) return 1; + if (tag == ao_lisp_busy) + total_marked += size; while (base < bound) { mark(tag, base); base += 4; @@ -126,12 +309,14 @@ mark_object(uint8_t *tag, void *addr, int size) { return 0; } +MDBG_DO( static int clear_object(uint8_t *tag, void *addr, int size) { int base; int bound; - if (!addr) - return 1; + + MDBG_DO(if (!AO_LISP_IS_POOL((uint8_t *) addr + size - 1)) + ao_lisp_abort()); base = (uint8_t *) addr - ao_lisp_pool; bound = base + size; @@ -140,29 +325,13 @@ clear_object(uint8_t *tag, void *addr, int size) { bound = limit(bound); if (!busy(tag, base)) return 1; + total_marked -= size; while (base < bound) { clear(tag, base); base += 4; } return 0; -} - -static int -busy_object(uint8_t *tag, void *addr) { - int base; - - if (!addr) - return 1; - - if ((uint8_t *) addr < ao_lisp_pool || ao_lisp_pool + AO_LISP_POOL <= (uint8_t*) addr) - return 1; - - base = (uint8_t *) addr - ao_lisp_pool; - base = limit(base); - if (busy(tag, base)) - return 1; - return 0; -} +}) static void note_cons(void *addr) @@ -175,31 +344,63 @@ note_cons(void *addr) } } +static uint16_t chunk_low; +static uint16_t chunk_first, chunk_last; + +static void +note_chunk(uint16_t addr, uint16_t size) +{ + int i; + + if (addr < chunk_low) + return; + + for (i = 0; i < AO_LISP_NCHUNK; i++) { + if (ao_lisp_chunk[i].size && ao_lisp_chunk[i].old_addr == addr) { + if (ao_lisp_chunk[i].size != size) + ao_lisp_abort(); + return; + } + if (ao_lisp_chunk[i].old_addr > addr) { + memmove(&ao_lisp_chunk[i+1], + &ao_lisp_chunk[i], + (AO_LISP_NCHUNK - (i+1)) * sizeof (struct ao_lisp_chunk)); + ao_lisp_chunk[i].size = 0; + } + if (ao_lisp_chunk[i].size == 0) { + ao_lisp_chunk[i].old_addr = addr; + ao_lisp_chunk[i].size = size; + return; + } + } +} + /* * Walk all referenced objects calling functions on each one */ static void -walk(uint8_t *tag, - int (*visit_addr)(const struct ao_lisp_type *type, void **addr), +walk(int (*visit_addr)(const struct ao_lisp_type *type, void **addr), int (*visit_poly)(ao_poly *p, uint8_t do_note_cons)) { int i; - memset(tag, '\0', sizeof (ao_lisp_busy)); + total_marked = 0; + ao_lisp_record_reset(); + memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy)); memset(ao_lisp_cons_note, '\0', sizeof (ao_lisp_cons_note)); ao_lisp_cons_noted = 0; for (i = 0; i < AO_LISP_ROOT; i++) { if (ao_lisp_root[i].type) { void **a = ao_lisp_root[i].addr, *v; if (a && (v = *a)) { - MDBG("root ptr %d\n", MDBG_OFFSET(v)); + MDBG_MOVE("root ptr %d\n", MDBG_OFFSET(v)); visit_addr(ao_lisp_root[i].type, a); } } else { ao_poly *a = (ao_poly *) ao_lisp_root[i].addr, p; if (a && (p = *a)) { - MDBG("root poly %d\n", MDBG_OFFSET(ao_lisp_ref(p))); + MDBG_MOVE("root poly %d\n", MDBG_OFFSET(ao_lisp_ref(p))); visit_poly(a, 0); } } @@ -211,33 +412,32 @@ walk(uint8_t *tag, for (i = 0; i < AO_LISP_POOL; i += 4) { if (busy(ao_lisp_cons_last, i)) { void *v = ao_lisp_pool + i; - MDBG("root cons %d\n", MDBG_OFFSET(v)); + MDBG_MOVE("root cons %d\n", MDBG_OFFSET(v)); visit_addr(&ao_lisp_cons_type, &v); } } } } -static void *move_old, *move_new; -static int move_size; - #if MDBG_DUMP static void dump_busy(void) { int i; - printf("busy:"); + MDBG_MOVE("busy:"); for (i = 0; i < ao_lisp_top; i += 4) { - if ((i & 0xff) == 0) - printf("\n"); + if ((i & 0xff) == 0) { + MDBG_MORE("\n"); + MDBG_MOVE("%s", ""); + } else if ((i & 0x1f) == 0) - printf(" "); + MDBG_MORE(" "); if (busy(ao_lisp_busy, i)) - putchar('*'); + MDBG_MORE("*"); else - putchar('-'); + MDBG_MORE("-"); } - printf ("\n"); + MDBG_MORE ("\n"); } #define DUMP_BUSY() dump_busy() #else @@ -272,183 +472,241 @@ ao_lisp_collect(void) { int i; int top; +#if DBG_MEM + int loops = 0; + int marked; + int moved; + struct ao_lisp_record *mark_record = NULL, *move_record = NULL; + + ++dbg_collects; + MDBG_MOVE("collect %d\n", dbg_collects); + marked = moved = 0; +#endif + chunk_low = 0; + top = 0; + for (;;) { + MDBG_DO(loops++); + MDBG_MOVE("move chunks from %d to %d\n", chunk_low, top); + /* Find the sizes of the first chunk of objects to move */ + memset(ao_lisp_chunk, '\0', sizeof (ao_lisp_chunk)); + walk(ao_lisp_mark_ref, ao_lisp_poly_mark_ref); +#if DBG_MEM + marked = total_marked; + + ao_lisp_record_free(mark_record); + mark_record = ao_lisp_record_save(); + if (mark_record && move_record) + ao_lisp_record_compare("mark", move_record, mark_record); + + if (moved && moved != marked) + ao_lisp_abort(); +#endif - MDBG("collect\n"); - /* Mark */ - walk(ao_lisp_busy, ao_lisp_mark_ref, ao_lisp_poly_mark_ref); + DUMP_BUSY(); - DUMP_BUSY(); - /* Compact */ - MDBG("find first busy\n"); - for (i = 0; i < ao_lisp_top; i += 4) { - if (!busy(ao_lisp_busy, i)) - break; - } - top = i; - while(i < ao_lisp_top) { - if (busy(ao_lisp_busy, i)) { - MDBG("busy %d -> %d\n", i, top); - MDBG_MOVE_IN(); - move_old = &ao_lisp_pool[i]; - move_new = &ao_lisp_pool[top]; - move_size = 0; - walk(ao_lisp_moving, ao_lisp_move, ao_lisp_poly_move); - MDBG("\tbusy size %d\n", move_size); - if (move_size == 0) + /* Find the first moving object */ + for (i = 0; i < AO_LISP_NCHUNK; i++) { + uint16_t size = ao_lisp_chunk[i].size; + + if (!size) + break; + + if (ao_lisp_chunk[i].old_addr > top) + break; + if (ao_lisp_chunk[i].old_addr != top) + ao_lisp_abort(); + + top += size; + MDBG_MOVE("chunk %d %d not moving\n", + ao_lisp_chunk[i].old_addr, + ao_lisp_chunk[i].size); + chunk_low = ao_lisp_chunk[i].old_addr + size; + } + + chunk_first = i; + /* Copy all of the objects */ + for (; i < AO_LISP_NCHUNK; i++) { + uint16_t size = ao_lisp_chunk[i].size; + + if (!size) + break; + + MDBG_MOVE("chunk %d %d -> %d\n", + ao_lisp_chunk[i].old_addr, + size, + top); + ao_lisp_chunk[i].new_addr = top; + memmove(&ao_lisp_pool[top], + &ao_lisp_pool[ao_lisp_chunk[i].old_addr], + size); + MDBG_DO(clear_object(ao_lisp_busy, &ao_lisp_pool[ao_lisp_chunk[i].old_addr], size)); + MDBG_DO(mark_object(ao_lisp_busy, &ao_lisp_pool[top], size)); + top += size; + chunk_low = ao_lisp_chunk[i].old_addr + size; + } + + MDBG_MOVE("after moving objects, busy is now:\n"); + DUMP_BUSY(); + chunk_last = i; + + if (chunk_first < chunk_last) { + /* Relocate all references to the objects */ + walk(ao_lisp_move, ao_lisp_poly_move); + +#if DBG_MEM + ao_lisp_record_free(move_record); + move_record = ao_lisp_record_save(); + if (mark_record && move_record) + ao_lisp_record_compare("move", mark_record, move_record); + + moved = total_marked; + if (moved != marked) ao_lisp_abort(); - clear_object(ao_lisp_busy, move_old, move_size); - mark_object(ao_lisp_busy, move_new, move_size); - if (busy_object(ao_lisp_cons_note, move_old)) { - clear_object(ao_lisp_cons_note, move_old, move_size); - mark_object(ao_lisp_cons_note, move_new, move_size); - } - i += move_size; - top += move_size; -#if MDBG_MOVE - DUMP_BUSY(); #endif - MDBG_MOVE_OUT(); - } else { - i += 4; } + + if (chunk_last != AO_LISP_NCHUNK) + break; } ao_lisp_top = top; + + MDBG_DO(memset(ao_lisp_chunk, '\0', sizeof (ao_lisp_chunk)); + walk(ao_lisp_mark_ref, ao_lisp_poly_mark_ref)); + +// printf ("collect. top %d loops %d\n", top, loops); } +/* + * Mark interfaces for objects + * + * Note a reference to memory and + * collect information about a few object sizes + * at a time + */ int -ao_lisp_mark(const struct ao_lisp_type *type, void *addr) +ao_lisp_mark_memory(const struct ao_lisp_type *type, void *addr) { - if (!addr) + int size; + if (!AO_LISP_IS_POOL(addr)) return 1; - MDBG_MOVE_IN(); + + size = ao_lisp_size(type, addr); + MDBG_MOVE("mark memory %d\n", MDBG_OFFSET(addr)); + if (!mark_object(ao_lisp_busy, addr, size)) { + note_chunk(pool_offset(addr), size); + MDBG_DO(ao_lisp_record(type, addr, size)); + return 0; + } + MDBG_MOVE("already marked\n"); + return 1; +} + +int +ao_lisp_mark(const struct ao_lisp_type *type, void *addr) +{ + int ret; MDBG_MOVE("mark %d\n", MDBG_OFFSET(addr)); - if (mark_object(ao_lisp_busy, addr, type->size(addr))) { - MDBG_MOVE("already marked\n"); - MDBG_MOVE_OUT(); - return 1; + MDBG_MOVE_IN(); + ret = ao_lisp_mark_memory(type, addr); + if (!ret) { + MDBG_MOVE("mark recurse\n"); + type->mark(addr); } - type->mark(addr); MDBG_MOVE_OUT(); - return 0; + return ret; } int ao_lisp_poly_mark(ao_poly p, uint8_t do_note_cons) { - uint8_t type = ao_lisp_poly_type(p); + uint8_t type; + void *addr; if (!p) return 1; + + type = ao_lisp_poly_base_type(p); + addr = ao_lisp_ref(p); + + if (!AO_LISP_IS_POOL(addr)) + return 1; + if (type == AO_LISP_CONS && do_note_cons) { - MDBG_MOVE("note cons %d\n", MDBG_OFFSET(ao_lisp_ref(p))); note_cons(ao_lisp_ref(p)); - return 0; - } else { - const struct ao_lisp_type *lisp_type = ao_lisp_types[ao_lisp_poly_type(p)]; - if (lisp_type) - return ao_lisp_mark(lisp_type, ao_lisp_ref(p)); return 1; - } -} + } else { + const struct ao_lisp_type *lisp_type; -int -ao_lisp_mark_memory(void *addr, int size) -{ - return mark_object(ao_lisp_busy, addr, size); -} + if (type == AO_LISP_OTHER) { + type = ao_lisp_other_type(ao_lisp_poly_other(p)); + if (type <= AO_LISP_OTHER || AO_LISP_NUM_TYPE <= type) + ao_lisp_abort(); + } -/* - * After the object has been moved, we have to reference it - * in the new location. This is only relevant for ao_lisp_poly_move - * as it needs to fetch the type byte from the object, which - * may have been overwritten by the copy - */ -void * -ao_lisp_move_map(void *addr) -{ - if (addr == move_old) { - if (move_size != 0) - return move_new; + lisp_type = ao_lisp_types[ao_lisp_poly_type(p)]; + if (!lisp_type) + return 1; + return ao_lisp_mark(lisp_type, ao_lisp_ref(p)); } - return addr; } static void * -check_move(void *addr, int size) +move_map(void *addr) { - if (addr == move_old) { - MDBG_MOVE("mapping %d -> %d\n", MDBG_OFFSET(addr), MDBG_OFFSET(move_new)); - if (move_size && move_size != ((size + 3) & ~3)) - ao_lisp_abort(); - - /* Only copy the object once, otherwise we may - * smash stuff - */ - if (move_size == 0) { - MDBG_MOVE(" copy %d\n", size); - memmove(move_new, move_old, size); - move_size = (size + 3) & ~3; + uint16_t offset = pool_offset(addr); + int i; + + for (i = chunk_first; i < chunk_last; i++) { + if (ao_lisp_chunk[i].old_addr == offset) { + MDBG_MOVE("move %d -> %d\n", + ao_lisp_chunk[i].old_addr, + ao_lisp_chunk[i].new_addr); + return ao_lisp_pool + ao_lisp_chunk[i].new_addr; } - addr = move_new; } return addr; } int -ao_lisp_move(const struct ao_lisp_type *type, void **ref) +ao_lisp_move_memory(const struct ao_lisp_type *type, void **ref) { void *addr = *ref; - uint8_t *a = addr; - int size = type->size(ao_lisp_move_map(addr)); + int size; - if (!addr) + if (!AO_LISP_IS_POOL(addr)) return 1; -#ifndef AO_LISP_MAKE_CONST - if (AO_LISP_IS_CONST(addr)) - return 1; -#endif - MDBG_MOVE("object %d\n", MDBG_OFFSET(addr)); - if (!AO_LISP_IS_POOL(a)) - ao_lisp_abort(); - MDBG_MOVE_IN(); - addr = check_move(addr, size); - if (addr != *ref) + MDBG_MOVE("move memory %d\n", MDBG_OFFSET(addr)); + addr = move_map(addr); + size = ao_lisp_size(type, addr); + if (addr != *ref) { + MDBG_MOVE("update ref %d %d -> %d\n", + AO_LISP_IS_POOL(ref) ? MDBG_OFFSET(ref) : -1, + MDBG_OFFSET(*ref), MDBG_OFFSET(addr)); *ref = addr; - if (mark_object(ao_lisp_moving, addr, size)) { - MDBG_MOVE("already moved\n"); - MDBG_MOVE_OUT(); - return 1; } - MDBG_MOVE_OUT(); - MDBG_MOVE("recursing...\n"); - MDBG_MOVE_IN(); - type->move(addr); - MDBG_MOVE_OUT(); - MDBG_MOVE("done %d\n", MDBG_OFFSET(addr)); - return 0; + if (!mark_object(ao_lisp_busy, addr, size)) { + MDBG_DO(ao_lisp_record(type, addr, size)); + return 0; + } + MDBG_MOVE("already moved\n"); + return 1; } int -ao_lisp_move_memory(void **ref, int size) +ao_lisp_move(const struct ao_lisp_type *type, void **ref) { - void *addr = *ref; - if (!addr) - return 1; - - MDBG_MOVE("memory %d\n", MDBG_OFFSET(addr)); + int ret; + MDBG_MOVE("move object %d\n", MDBG_OFFSET(*ref)); MDBG_MOVE_IN(); - addr = check_move(addr, size); - if (addr != *ref) - *ref = addr; - if (mark_object(ao_lisp_moving, addr, size)) { - MDBG_MOVE("already moved\n"); - MDBG_MOVE_OUT(); - return 1; + ret = ao_lisp_move_memory(type, ref); + if (!ret) { + MDBG_MOVE("move recurse\n"); + type->move(*ref); } MDBG_MOVE_OUT(); - return 0; + return ret; } int @@ -456,7 +714,6 @@ ao_lisp_poly_move(ao_poly *ref, uint8_t do_note_cons) { uint8_t type; ao_poly p = *ref; - const struct ao_lisp_type *lisp_type; int ret; void *addr; @@ -466,20 +723,24 @@ ao_lisp_poly_move(ao_poly *ref, uint8_t do_note_cons) type = ao_lisp_poly_base_type(p); addr = ao_lisp_ref(p); - if ((uint8_t *) addr < ao_lisp_pool || ao_lisp_pool + AO_LISP_POOL <= (uint8_t*) addr) + if (!AO_LISP_IS_POOL(addr)) return 1; if (type == AO_LISP_CONS && do_note_cons) { - addr = check_move(addr, sizeof (struct ao_lisp_cons)); +// addr = move_map(addr); + MDBG_DO(if (addr != move_map(addr)) MDBG_MOVE("noting cons at old addr %d instead of new addr %d\n", MDBG_OFFSET(addr), MDBG_OFFSET(move_map(addr)));); + note_cons(addr); + addr = move_map(addr); ret = 1; } else { + const struct ao_lisp_type *lisp_type; - if (type == AO_LISP_OTHER) - type = ao_lisp_other_type(ao_lisp_move_map(ao_lisp_poly_other(p))); - - if (type >= AO_LISP_NUM_TYPE) - ao_lisp_abort(); + if (type == AO_LISP_OTHER) { + type = ao_lisp_other_type(move_map(ao_lisp_poly_other(p))); + if (type <= AO_LISP_OTHER || AO_LISP_NUM_TYPE <= type) + ao_lisp_abort(); + } lisp_type = ao_lisp_types[type]; if (!lisp_type) @@ -487,10 +748,11 @@ ao_lisp_poly_move(ao_poly *ref, uint8_t do_note_cons) ret = ao_lisp_move(lisp_type, &addr); } + /* Re-write the poly value */ if (addr != ao_lisp_ref(p)) { ao_poly np = ao_lisp_poly(addr, p & AO_LISP_TYPE_MASK); - MDBG("poly %d moved %d -> %d\n", - type, MDBG_OFFSET(ao_lisp_ref(p)), MDBG_OFFSET(ao_lisp_ref(np))); + MDBG_MOVE("poly %d moved %d -> %d\n", + type, MDBG_OFFSET(ao_lisp_ref(p)), MDBG_OFFSET(ao_lisp_ref(np))); *ref = np; } return ret; @@ -535,15 +797,28 @@ ao_lisp_poison(void) #define AO_LISP_POOL_CUR AO_LISP_POOL #endif +#if DBG_MEM +void +ao_lisp_validate(void) +{ + chunk_low = 0; + memset(ao_lisp_chunk, '\0', sizeof (ao_lisp_chunk)); + walk(ao_lisp_mark_ref, ao_lisp_poly_mark_ref); +} + +int dbg_allocs; + +#endif + + void * ao_lisp_alloc(int size) { void *addr; - size = ao_lisp_mem_round(size); -#ifdef MDBG_COLLECT_ALWAYS - ao_lisp_collect(); -#endif + MDBG_DO(++dbg_allocs); + MDBG_DO(if (dbg_validate) ao_lisp_validate()); + size = ao_lisp_size_round(size); if (ao_lisp_top + size > AO_LISP_POOL_CUR) { #ifdef MDBG_POOL if (AO_LISP_POOL_CUR < AO_LISP_POOL) { @@ -573,37 +848,47 @@ ao_lisp_alloc(int size) return addr; } -int -ao_lisp_root_add(const struct ao_lisp_type *type, void *addr) +void +ao_lisp_cons_stash(int id, struct ao_lisp_cons *cons) { - int i; - MDBG("add root type %p addr %p\n", type, addr); - for (i = 0; i < AO_LISP_ROOT; i++) { - if (!ao_lisp_root[i].addr) { - ao_lisp_root[i].addr = addr; - ao_lisp_root[i].type = type; - return 1; - } - } - ao_lisp_abort(); - return 0; + if (save_cons[id] != NULL) + ao_lisp_abort(); + save_cons[id] = cons; } -int -ao_lisp_root_poly_add(ao_poly *p) +struct ao_lisp_cons * +ao_lisp_cons_fetch(int id) { - return ao_lisp_root_add(NULL, p); + struct ao_lisp_cons *cons = save_cons[id]; + save_cons[id] = NULL; + return cons; } void -ao_lisp_root_clear(void *addr) +ao_lisp_string_stash(int id, char *string) { - int i; - for (i = 0; i < AO_LISP_ROOT; i++) { - if (ao_lisp_root[i].addr == addr) { - ao_lisp_root[i].addr = 0; - ao_lisp_root[i].type = 0; - break; - } - } + if (save_cons[id] != NULL) + ao_lisp_abort(); + save_string[id] = string; +} + +char * +ao_lisp_string_fetch(int id) +{ + char *string = save_string[id]; + save_string[id] = NULL; + return string; +} +void +ao_lisp_poly_stash(int id, ao_poly poly) +{ + save_poly[id] = poly; +} + +ao_poly +ao_lisp_poly_fetch(int id) +{ + ao_poly poly = save_poly[id]; + save_poly[id] = AO_LISP_NIL; + return poly; } diff --git a/src/lisp/ao_lisp_read.c b/src/lisp/ao_lisp_read.c index 7a5751ce..b792c2f1 100644 --- a/src/lisp/ao_lisp_read.c +++ b/src/lisp/ao_lisp_read.c @@ -357,25 +357,25 @@ lex(void) } static int parse_token; -static uint8_t been_here; -static struct ao_lisp_cons *read_cons; -static struct ao_lisp_cons *read_cons_tail; -static struct ao_lisp_cons *read_stack; + +struct ao_lisp_cons *ao_lisp_read_cons; +struct ao_lisp_cons *ao_lisp_read_cons_tail; +struct ao_lisp_cons *ao_lisp_read_stack; static int push_read_stack(int cons, int in_quote) { - DBGI("push read stack %p %d\n", read_cons, in_quote); + DBGI("push read stack %p %d\n", ao_lisp_read_cons, in_quote); DBG_IN(); if (cons) { - read_stack = ao_lisp_cons_cons(ao_lisp_cons_poly(read_cons), + ao_lisp_read_stack = ao_lisp_cons_cons(ao_lisp_cons_poly(ao_lisp_read_cons), ao_lisp_cons_cons(ao_lisp_int_poly(in_quote), - read_stack)); - if (!read_stack) + ao_lisp_read_stack)); + if (!ao_lisp_read_stack) return 0; } - read_cons = NULL; - read_cons_tail = NULL; + ao_lisp_read_cons = NULL; + ao_lisp_read_cons_tail = NULL; return 1; } @@ -384,21 +384,21 @@ pop_read_stack(int cons) { int in_quote = 0; if (cons) { - read_cons = ao_lisp_poly_cons(read_stack->car); - read_stack = ao_lisp_poly_cons(read_stack->cdr); - in_quote = ao_lisp_poly_int(read_stack->car); - read_stack = ao_lisp_poly_cons(read_stack->cdr); - for (read_cons_tail = read_cons; - read_cons_tail && read_cons_tail->cdr; - read_cons_tail = ao_lisp_poly_cons(read_cons_tail->cdr)) + ao_lisp_read_cons = ao_lisp_poly_cons(ao_lisp_read_stack->car); + ao_lisp_read_stack = ao_lisp_poly_cons(ao_lisp_read_stack->cdr); + in_quote = ao_lisp_poly_int(ao_lisp_read_stack->car); + ao_lisp_read_stack = ao_lisp_poly_cons(ao_lisp_read_stack->cdr); + for (ao_lisp_read_cons_tail = ao_lisp_read_cons; + ao_lisp_read_cons_tail && ao_lisp_read_cons_tail->cdr; + ao_lisp_read_cons_tail = ao_lisp_poly_cons(ao_lisp_read_cons_tail->cdr)) ; } else { - read_cons = 0; - read_cons_tail = 0; - read_stack = 0; + ao_lisp_read_cons = 0; + ao_lisp_read_cons_tail = 0; + ao_lisp_read_stack = 0; } DBG_OUT(); - DBGI("pop read stack %p %d\n", read_cons, in_quote); + DBGI("pop read stack %p %d\n", ao_lisp_read_cons, in_quote); return in_quote; } @@ -411,18 +411,12 @@ ao_lisp_read(void) int in_quote; ao_poly v; - if (!been_here) { - ao_lisp_root_add(&ao_lisp_cons_type, &read_cons); - ao_lisp_root_add(&ao_lisp_cons_type, &read_cons_tail); - ao_lisp_root_add(&ao_lisp_cons_type, &read_stack); - been_here = 1; - } parse_token = lex(); DBGI("token %d (%s)\n", parse_token, token_string); cons = 0; in_quote = 0; - read_cons = read_cons_tail = read_stack = 0; + ao_lisp_read_cons = ao_lisp_read_cons_tail = ao_lisp_read_stack = 0; for (;;) { while (parse_token == OPEN) { if (!push_read_stack(cons, in_quote)) @@ -469,7 +463,7 @@ ao_lisp_read(void) v = AO_LISP_NIL; break; } - v = ao_lisp_cons_poly(read_cons); + v = ao_lisp_cons_poly(ao_lisp_read_cons); --cons; in_quote = pop_read_stack(cons); break; @@ -484,16 +478,16 @@ ao_lisp_read(void) if (!read) return AO_LISP_NIL; - if (read_cons_tail) - read_cons_tail->cdr = ao_lisp_cons_poly(read); + if (ao_lisp_read_cons_tail) + ao_lisp_read_cons_tail->cdr = ao_lisp_cons_poly(read); else - read_cons = read; - read_cons_tail = read; + ao_lisp_read_cons = read; + ao_lisp_read_cons_tail = read; - if (!in_quote || !read_cons->cdr) + if (!in_quote || !ao_lisp_read_cons->cdr) break; - v = ao_lisp_cons_poly(read_cons); + v = ao_lisp_cons_poly(ao_lisp_read_cons); --cons; in_quote = pop_read_stack(cons); } diff --git a/src/lisp/ao_lisp_string.c b/src/lisp/ao_lisp_string.c index 9ee1a7dd..207d4f3b 100644 --- a/src/lisp/ao_lisp_string.c +++ b/src/lisp/ao_lisp_string.c @@ -38,23 +38,17 @@ const struct ao_lisp_type ao_lisp_string_type = { .mark = string_mark, .size = string_size, .move = string_move, + .name = "string", }; -char * -ao_lisp_string_new(int len) { - char *a = ao_lisp_alloc(len + 1); - if (!a) - return NULL; - a[len] = '\0'; - return a; -} - char * ao_lisp_string_copy(char *a) { int alen = strlen(a); + ao_lisp_string_stash(0, a); char *r = ao_lisp_alloc(alen + 1); + a = ao_lisp_string_fetch(0); if (!r) return NULL; strcpy(r, a); @@ -66,7 +60,12 @@ ao_lisp_string_cat(char *a, char *b) { int alen = strlen(a); int blen = strlen(b); + + ao_lisp_string_stash(0, a); + ao_lisp_string_stash(1, b); char *r = ao_lisp_alloc(alen + blen + 1); + a = ao_lisp_string_fetch(0); + b = ao_lisp_string_fetch(1); if (!r) return NULL; strcpy(r, a); @@ -78,7 +77,9 @@ ao_poly ao_lisp_string_pack(struct ao_lisp_cons *cons) { int len = ao_lisp_cons_length(cons); + ao_lisp_cons_stash(0, cons); char *r = ao_lisp_alloc(len + 1); + cons = ao_lisp_cons_fetch(0); char *s = r; while (cons) { @@ -96,11 +97,17 @@ ao_lisp_string_unpack(char *a) { struct ao_lisp_cons *cons = NULL, *tail = NULL; int c; + int i; - ao_lisp_root_add(&ao_lisp_cons_type, &cons); - ao_lisp_root_add(&ao_lisp_cons_type, &tail); - while ((c = *a++)) { + for (i = 0; (c = a[i]); i++) { + ao_lisp_cons_stash(0, cons); + ao_lisp_cons_stash(1, tail); + ao_lisp_string_stash(0, a); struct ao_lisp_cons *n = ao_lisp_cons_cons(ao_lisp_int_poly(c), NULL); + cons = ao_lisp_cons_fetch(0); + tail = ao_lisp_cons_fetch(1); + a = ao_lisp_string_fetch(0); + if (!n) { cons = NULL; break; @@ -111,8 +118,6 @@ ao_lisp_string_unpack(char *a) cons = n; tail = n; } - ao_lisp_root_clear(&cons); - ao_lisp_root_clear(&tail); return ao_lisp_cons_poly(cons); } -- cgit v1.2.3 From ce549b2c11e6b2571590021e1c0503d8a6e7a702 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 14 Nov 2016 19:55:36 -0800 Subject: altos/lisp: Simplify GC a bit by only marking the head of each object We don't need to mark the whole object now as we're getting information about where objects are by walking the tree each time around the loop; ao_lisp_busy is only useful for terminating the walk now. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 2 +- src/lisp/ao_lisp_mem.c | 94 ++++++++++---------------------------------------- 2 files changed, 20 insertions(+), 76 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 906bae19..e90d791a 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -650,7 +650,7 @@ ao_lisp_frames_dump(void) #define DBG_FRAMES() #endif -#define DBG_MEM 1 +#define DBG_MEM 0 #define DBG_MEM_START 1 #if DBG_MEM diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 60f4bbee..08b5bac0 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -282,62 +282,11 @@ static inline int limit(int offset) { static int total_marked; -/* - * Mark a range of addresses - */ -static int -mark_object(uint8_t *tag, void *addr, int size) { - int base; - int bound; - - MDBG_DO(if (!AO_LISP_IS_POOL((uint8_t *) addr + size - 1)) - ao_lisp_abort()); - - base = pool_offset(addr); - bound = base + size; - - MDBG_DO(if (bound > ao_lisp_top) ao_lisp_abort()); - - if (busy(tag, base)) - return 1; - if (tag == ao_lisp_busy) - total_marked += size; - while (base < bound) { - mark(tag, base); - base += 4; - } - return 0; -} - -MDBG_DO( -static int -clear_object(uint8_t *tag, void *addr, int size) { - int base; - int bound; - - MDBG_DO(if (!AO_LISP_IS_POOL((uint8_t *) addr + size - 1)) - ao_lisp_abort()); - - base = (uint8_t *) addr - ao_lisp_pool; - bound = base + size; - - base = limit(base); - bound = limit(bound); - if (!busy(tag, base)) - return 1; - total_marked -= size; - while (base < bound) { - clear(tag, base); - base += 4; - } - return 0; -}) - static void note_cons(void *addr) { if (AO_LISP_IS_POOL(addr)) { - int offset = (uint8_t *) addr - ao_lisp_pool; + int offset = pool_offset(addr); MDBG_MOVE("note cons %d\n", MDBG_OFFSET(addr)); ao_lisp_cons_noted = 1; mark(ao_lisp_cons_note, offset); @@ -539,14 +488,10 @@ ao_lisp_collect(void) memmove(&ao_lisp_pool[top], &ao_lisp_pool[ao_lisp_chunk[i].old_addr], size); - MDBG_DO(clear_object(ao_lisp_busy, &ao_lisp_pool[ao_lisp_chunk[i].old_addr], size)); - MDBG_DO(mark_object(ao_lisp_busy, &ao_lisp_pool[top], size)); top += size; chunk_low = ao_lisp_chunk[i].old_addr + size; } - MDBG_MOVE("after moving objects, busy is now:\n"); - DUMP_BUSY(); chunk_last = i; if (chunk_first < chunk_last) { @@ -587,19 +532,19 @@ ao_lisp_collect(void) int ao_lisp_mark_memory(const struct ao_lisp_type *type, void *addr) { - int size; + int offset; if (!AO_LISP_IS_POOL(addr)) return 1; - size = ao_lisp_size(type, addr); + offset = pool_offset(addr); MDBG_MOVE("mark memory %d\n", MDBG_OFFSET(addr)); - if (!mark_object(ao_lisp_busy, addr, size)) { - note_chunk(pool_offset(addr), size); - MDBG_DO(ao_lisp_record(type, addr, size)); - return 0; + if (busy(ao_lisp_busy, offset)) { + MDBG_MOVE("already marked\n"); + return 1; } - MDBG_MOVE("already marked\n"); - return 1; + mark(ao_lisp_busy, offset); + note_chunk(offset, ao_lisp_size(type, addr)); + return 0; } int @@ -672,26 +617,27 @@ int ao_lisp_move_memory(const struct ao_lisp_type *type, void **ref) { void *addr = *ref; - int size; + int offset; if (!AO_LISP_IS_POOL(addr)) return 1; MDBG_MOVE("move memory %d\n", MDBG_OFFSET(addr)); addr = move_map(addr); - size = ao_lisp_size(type, addr); if (addr != *ref) { MDBG_MOVE("update ref %d %d -> %d\n", AO_LISP_IS_POOL(ref) ? MDBG_OFFSET(ref) : -1, MDBG_OFFSET(*ref), MDBG_OFFSET(addr)); *ref = addr; } - if (!mark_object(ao_lisp_busy, addr, size)) { - MDBG_DO(ao_lisp_record(type, addr, size)); - return 0; + offset = pool_offset(addr); + if (busy(ao_lisp_busy, offset)) { + MDBG_MOVE("already moved\n"); + return 1; } - MDBG_MOVE("already moved\n"); - return 1; + mark(ao_lisp_busy, offset); + MDBG_DO(ao_lisp_record(type, addr, ao_lisp_size(type, addr))); + return 0; } int @@ -720,16 +666,14 @@ ao_lisp_poly_move(ao_poly *ref, uint8_t do_note_cons) if (!p) return 1; - type = ao_lisp_poly_base_type(p); addr = ao_lisp_ref(p); if (!AO_LISP_IS_POOL(addr)) return 1; - if (type == AO_LISP_CONS && do_note_cons) { -// addr = move_map(addr); - MDBG_DO(if (addr != move_map(addr)) MDBG_MOVE("noting cons at old addr %d instead of new addr %d\n", MDBG_OFFSET(addr), MDBG_OFFSET(move_map(addr)));); + type = ao_lisp_poly_base_type(p); + if (type == AO_LISP_CONS && do_note_cons) { note_cons(addr); addr = move_map(addr); ret = 1; -- cgit v1.2.3 From 5557f6b87a9b8bc9716de8191f2062a772a6ae6c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 14 Nov 2016 21:25:38 -0800 Subject: altos/lisp: Cache freed cons and stack items Track freed cons cells and stack items from the eval process where possible so that they can be re-used without needing to collect. This dramatically reduces the number of collect calls. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 17 ++++++++++++++ src/lisp/ao_lisp_cons.c | 32 +++++++++++++++++++------ src/lisp/ao_lisp_eval.c | 33 +++++++++++++++++++++----- src/lisp/ao_lisp_lambda.c | 1 + src/lisp/ao_lisp_make_const.c | 54 +++++++++++++++++++++---------------------- src/lisp/ao_lisp_mem.c | 41 ++++++++++++++++++++++++-------- src/lisp/ao_lisp_save.c | 2 +- 7 files changed, 130 insertions(+), 50 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index e90d791a..efd13cf5 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -206,6 +206,7 @@ ao_lisp_stack_poly(struct ao_lisp_stack *stack) } extern struct ao_lisp_stack *ao_lisp_stack; +extern struct ao_lisp_stack *ao_lisp_stack_free_list; extern ao_poly ao_lisp_v; #define AO_LISP_FUNC_LAMBDA 0 @@ -213,6 +214,14 @@ extern ao_poly ao_lisp_v; #define AO_LISP_FUNC_MACRO 2 #define AO_LISP_FUNC_LEXPR 3 +#define AO_LISP_FUNC_FREE_ARGS 0x80 +#define AO_LISP_FUNC_MASK 0x7f + +#define AO_LISP_FUNC_F_LAMBDA (AO_LISP_FUNC_FREE_ARGS | AO_LISP_FUNC_LAMBDA) +#define AO_LISP_FUNC_F_NLAMBDA (AO_LISP_FUNC_FREE_ARGS | AO_LISP_FUNC_NLAMBDA) +#define AO_LISP_FUNC_F_MACRO (AO_LISP_FUNC_FREE_ARGS | AO_LISP_FUNC_MACRO) +#define AO_LISP_FUNC_F_LEXPR (AO_LISP_FUNC_FREE_ARGS | AO_LISP_FUNC_LEXPR) + struct ao_lisp_builtin { uint8_t type; uint8_t args; @@ -390,6 +399,9 @@ ao_lisp_builtin_poly(struct ao_lisp_builtin *b) } /* memory functions */ + +extern int ao_lisp_collects; + /* returns 1 if the object was already marked */ int ao_lisp_mark(const struct ao_lisp_type *type, void *addr); @@ -439,6 +451,11 @@ extern const struct ao_lisp_type ao_lisp_cons_type; struct ao_lisp_cons * ao_lisp_cons_cons(ao_poly car, struct ao_lisp_cons *cdr); +extern struct ao_lisp_cons *ao_lisp_cons_free_list; + +void +ao_lisp_cons_free(struct ao_lisp_cons *cons); + void ao_lisp_cons_print(ao_poly); diff --git a/src/lisp/ao_lisp_cons.c b/src/lisp/ao_lisp_cons.c index 311d63ab..d2b60c9a 100644 --- a/src/lisp/ao_lisp_cons.c +++ b/src/lisp/ao_lisp_cons.c @@ -69,23 +69,41 @@ const struct ao_lisp_type ao_lisp_cons_type = { .name = "cons", }; +struct ao_lisp_cons *ao_lisp_cons_free_list; + struct ao_lisp_cons * ao_lisp_cons_cons(ao_poly car, struct ao_lisp_cons *cdr) { struct ao_lisp_cons *cons; - ao_lisp_poly_stash(0, car); - ao_lisp_cons_stash(0, cdr); - cons = ao_lisp_alloc(sizeof (struct ao_lisp_cons)); - car = ao_lisp_poly_fetch(0); - cdr = ao_lisp_cons_fetch(0); - if (!cons) - return NULL; + if (ao_lisp_cons_free_list) { + cons = ao_lisp_cons_free_list; + ao_lisp_cons_free_list = ao_lisp_poly_cons(cons->cdr); + } else { + ao_lisp_poly_stash(0, car); + ao_lisp_cons_stash(0, cdr); + cons = ao_lisp_alloc(sizeof (struct ao_lisp_cons)); + car = ao_lisp_poly_fetch(0); + cdr = ao_lisp_cons_fetch(0); + if (!cons) + return NULL; + } cons->car = car; cons->cdr = ao_lisp_cons_poly(cdr); return cons; } +void +ao_lisp_cons_free(struct ao_lisp_cons *cons) +{ + while (cons) { + ao_poly cdr = cons->cdr; + cons->cdr = ao_lisp_cons_poly(ao_lisp_cons_free_list); + ao_lisp_cons_free_list = cons; + cons = ao_lisp_poly_cons(cdr); + } +} + void ao_lisp_cons_print(ao_poly c) { diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index 04d0e70a..5cc1b75a 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -76,6 +76,8 @@ const struct ao_lisp_type ao_lisp_stack_type = { struct ao_lisp_stack *ao_lisp_stack; ao_poly ao_lisp_v; +struct ao_lisp_stack *ao_lisp_stack_free_list; + ao_poly ao_lisp_set_cond(struct ao_lisp_cons *c) { @@ -97,9 +99,15 @@ ao_lisp_stack_reset(struct ao_lisp_stack *stack) static int ao_lisp_stack_push(void) { - struct ao_lisp_stack *stack = ao_lisp_alloc(sizeof (struct ao_lisp_stack)); - if (!stack) - return 0; + struct ao_lisp_stack *stack; + if (ao_lisp_stack_free_list) { + stack = ao_lisp_stack_free_list; + ao_lisp_stack_free_list = ao_lisp_poly_stack(stack->prev); + } else { + stack = ao_lisp_alloc(sizeof (struct ao_lisp_stack)); + if (!stack) + return 0; + } stack->prev = ao_lisp_stack_poly(ao_lisp_stack); stack->frame = ao_lisp_frame_poly(ao_lisp_frame_current); stack->list = AO_LISP_NIL; @@ -114,9 +122,15 @@ ao_lisp_stack_push(void) static void ao_lisp_stack_pop(void) { + ao_poly prev; + if (!ao_lisp_stack) return; - ao_lisp_stack = ao_lisp_poly_stack(ao_lisp_stack->prev); + prev = ao_lisp_stack->prev; + ao_lisp_stack->prev = ao_lisp_stack_poly(ao_lisp_stack_free_list); + ao_lisp_stack_free_list = ao_lisp_stack; + + ao_lisp_stack = ao_lisp_poly_stack(prev); if (ao_lisp_stack) ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->frame); else @@ -141,7 +155,7 @@ func_type(ao_poly func) return ao_lisp_error(AO_LISP_INVALID, "func is nil"); switch (ao_lisp_poly_type(func)) { case AO_LISP_BUILTIN: - return ao_lisp_poly_builtin(func)->args; + return ao_lisp_poly_builtin(func)->args & AO_LISP_FUNC_MASK; case AO_LISP_LAMBDA: return ao_lisp_poly_lambda(func)->args; default: @@ -359,12 +373,15 @@ static int ao_lisp_eval_exec(void) { ao_poly v; + struct ao_lisp_builtin *builtin; + DBGI("exec: "); DBG_POLY(ao_lisp_v); DBG(" values "); DBG_POLY(ao_lisp_stack->values); DBG ("\n"); ao_lisp_stack->sexprs = AO_LISP_NIL; switch (ao_lisp_poly_type(ao_lisp_v)) { case AO_LISP_BUILTIN: ao_lisp_stack->state = eval_val; - v = ao_lisp_func(ao_lisp_poly_builtin(ao_lisp_v)) ( + builtin = ao_lisp_poly_builtin(ao_lisp_v); + v = ao_lisp_func(builtin) ( ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->values)->cdr)); DBG_DO(if (!ao_lisp_exception && ao_lisp_poly_builtin(ao_lisp_v)->func == builtin_set) { struct ao_lisp_cons *cons = ao_lisp_poly_cons(ao_lisp_stack->values); @@ -372,6 +389,10 @@ ao_lisp_eval_exec(void) ao_poly val = ao_lisp_arg(cons, 2); DBGI("set "); DBG_POLY(atom); DBG(" = "); DBG_POLY(val); DBG("\n"); }); + builtin = ao_lisp_poly_builtin(ao_lisp_v); + if (builtin->args & AO_LISP_FUNC_FREE_ARGS) + ao_lisp_cons_free(ao_lisp_poly_cons(ao_lisp_stack->values)); + ao_lisp_v = v; DBGI(".. result "); DBG_POLY(ao_lisp_v); DBG ("\n"); DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); diff --git a/src/lisp/ao_lisp_lambda.c b/src/lisp/ao_lisp_lambda.c index 6020a8b8..0dd8c698 100644 --- a/src/lisp/ao_lisp_lambda.c +++ b/src/lisp/ao_lisp_lambda.c @@ -168,6 +168,7 @@ ao_lisp_lambda_eval(void) args = ao_lisp_poly_cons(args->cdr); vals = ao_lisp_poly_cons(vals->cdr); } + ao_lisp_cons_free(cons); break; } case AO_LISP_FUNC_LEXPR: diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index 6a29f402..178b041e 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -33,42 +33,42 @@ struct builtin_func { }; struct builtin_func funcs[] = { - "eval", AO_LISP_FUNC_LAMBDA, builtin_eval, - "read", AO_LISP_FUNC_LAMBDA, builtin_read, + "eval", AO_LISP_FUNC_F_LAMBDA, builtin_eval, + "read", AO_LISP_FUNC_F_LAMBDA, builtin_read, "lambda", AO_LISP_FUNC_NLAMBDA, builtin_lambda, "lexpr", AO_LISP_FUNC_NLAMBDA, builtin_lexpr, "nlambda", AO_LISP_FUNC_NLAMBDA, builtin_nlambda, "macro", AO_LISP_FUNC_NLAMBDA, builtin_macro, - "car", AO_LISP_FUNC_LAMBDA, builtin_car, - "cdr", AO_LISP_FUNC_LAMBDA, builtin_cdr, - "cons", AO_LISP_FUNC_LAMBDA, builtin_cons, - "last", AO_LISP_FUNC_LAMBDA, builtin_last, - "length", AO_LISP_FUNC_LAMBDA, builtin_length, + "car", AO_LISP_FUNC_F_LAMBDA, builtin_car, + "cdr", AO_LISP_FUNC_F_LAMBDA, builtin_cdr, + "cons", AO_LISP_FUNC_F_LAMBDA, builtin_cons, + "last", AO_LISP_FUNC_F_LAMBDA, builtin_last, + "length", AO_LISP_FUNC_F_LAMBDA, builtin_length, "quote", AO_LISP_FUNC_NLAMBDA, builtin_quote, - "set", AO_LISP_FUNC_LAMBDA, builtin_set, + "set", AO_LISP_FUNC_F_LAMBDA, builtin_set, "setq", AO_LISP_FUNC_MACRO, builtin_setq, "cond", AO_LISP_FUNC_NLAMBDA, builtin_cond, "progn", AO_LISP_FUNC_NLAMBDA, builtin_progn, "while", AO_LISP_FUNC_NLAMBDA, builtin_while, - "print", AO_LISP_FUNC_LEXPR, builtin_print, - "patom", AO_LISP_FUNC_LEXPR, builtin_patom, - "+", AO_LISP_FUNC_LEXPR, builtin_plus, - "-", AO_LISP_FUNC_LEXPR, builtin_minus, - "*", AO_LISP_FUNC_LEXPR, builtin_times, - "/", AO_LISP_FUNC_LEXPR, builtin_divide, - "%", AO_LISP_FUNC_LEXPR, builtin_mod, - "=", AO_LISP_FUNC_LEXPR, builtin_equal, - "<", AO_LISP_FUNC_LEXPR, builtin_less, - ">", AO_LISP_FUNC_LEXPR, builtin_greater, - "<=", AO_LISP_FUNC_LEXPR, builtin_less_equal, - ">=", AO_LISP_FUNC_LEXPR, builtin_greater_equal, - "pack", AO_LISP_FUNC_LAMBDA, builtin_pack, - "unpack", AO_LISP_FUNC_LAMBDA, builtin_unpack, - "flush", AO_LISP_FUNC_LAMBDA, builtin_flush, - "delay", AO_LISP_FUNC_LAMBDA, builtin_delay, - "led", AO_LISP_FUNC_LEXPR, builtin_led, - "save", AO_LISP_FUNC_LAMBDA, builtin_save, - "restore", AO_LISP_FUNC_LAMBDA, builtin_restore, + "print", AO_LISP_FUNC_F_LEXPR, builtin_print, + "patom", AO_LISP_FUNC_F_LEXPR, builtin_patom, + "+", AO_LISP_FUNC_F_LEXPR, builtin_plus, + "-", AO_LISP_FUNC_F_LEXPR, builtin_minus, + "*", AO_LISP_FUNC_F_LEXPR, builtin_times, + "/", AO_LISP_FUNC_F_LEXPR, builtin_divide, + "%", AO_LISP_FUNC_F_LEXPR, builtin_mod, + "=", AO_LISP_FUNC_F_LEXPR, builtin_equal, + "<", AO_LISP_FUNC_F_LEXPR, builtin_less, + ">", AO_LISP_FUNC_F_LEXPR, builtin_greater, + "<=", AO_LISP_FUNC_F_LEXPR, builtin_less_equal, + ">=", AO_LISP_FUNC_F_LEXPR, builtin_greater_equal, + "pack", AO_LISP_FUNC_F_LAMBDA, builtin_pack, + "unpack", AO_LISP_FUNC_F_LAMBDA, builtin_unpack, + "flush", AO_LISP_FUNC_F_LAMBDA, builtin_flush, + "delay", AO_LISP_FUNC_F_LAMBDA, builtin_delay, + "led", AO_LISP_FUNC_F_LEXPR, builtin_led, + "save", AO_LISP_FUNC_F_LAMBDA, builtin_save, + "restore", AO_LISP_FUNC_F_LAMBDA, builtin_restore, }; #define N_FUNC (sizeof funcs / sizeof funcs[0]) diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 08b5bac0..e7ece960 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -43,7 +43,6 @@ uint8_t ao_lisp_pool[AO_LISP_POOL + AO_LISP_POOL_EXTRA] __attribute__((aligned(4 #if DBG_MEM int dbg_move_depth; int dbg_mem = DBG_MEM_START; -int dbg_collects = 0; int dbg_validate = 0; struct ao_lisp_record { @@ -212,6 +211,13 @@ static const struct ao_lisp_root ao_lisp_root[] = { #define AO_LISP_ROOT (sizeof (ao_lisp_root) / sizeof (ao_lisp_root[0])) +static const void ** const ao_lisp_cache[] = { + (const void **) &ao_lisp_cons_free_list, + (const void **) &ao_lisp_stack_free_list, +}; + +#define AO_LISP_CACHE (sizeof (ao_lisp_cache) / sizeof (ao_lisp_cache[0])) + #define AO_LISP_BUSY_SIZE ((AO_LISP_POOL + 31) / 32) static uint8_t ao_lisp_busy[AO_LISP_BUSY_SIZE]; @@ -229,14 +235,16 @@ struct ao_lisp_chunk { }; }; -#define AO_LISP_NCHUNK 32 +#define AO_LISP_NCHUNK 64 static struct ao_lisp_chunk ao_lisp_chunk[AO_LISP_NCHUNK]; /* Offset of an address within the pool. */ static inline uint16_t pool_offset(void *addr) { +#if DBG_MEM if (!AO_LISP_IS_POOL(addr)) ao_lisp_abort(); +#endif return ((uint8_t *) addr) - ao_lisp_pool; } @@ -246,8 +254,10 @@ static inline uint16_t pool_offset(void *addr) { * These are used in the chunk code. */ static inline ao_poly pool_poly(void *addr) { +#if DBG_MEM if (!AO_LISP_IS_POOL(addr)) ao_lisp_abort(); +#endif return ((uint8_t *) addr) - AO_LISP_POOL_BASE; } @@ -306,8 +316,10 @@ note_chunk(uint16_t addr, uint16_t size) for (i = 0; i < AO_LISP_NCHUNK; i++) { if (ao_lisp_chunk[i].size && ao_lisp_chunk[i].old_addr == addr) { +#if DBG_MEM if (ao_lisp_chunk[i].size != size) ao_lisp_abort(); +#endif return; } if (ao_lisp_chunk[i].old_addr > addr) { @@ -339,7 +351,7 @@ walk(int (*visit_addr)(const struct ao_lisp_type *type, void **addr), memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy)); memset(ao_lisp_cons_note, '\0', sizeof (ao_lisp_cons_note)); ao_lisp_cons_noted = 0; - for (i = 0; i < AO_LISP_ROOT; i++) { + for (i = 0; i < (int) AO_LISP_ROOT; i++) { if (ao_lisp_root[i].type) { void **a = ao_lisp_root[i].addr, *v; if (a && (v = *a)) { @@ -416,6 +428,8 @@ ao_lisp_poly_mark_ref(ao_poly *p, uint8_t do_note_cons) return ao_lisp_poly_mark(*p, do_note_cons); } +int ao_lisp_collects; + void ao_lisp_collect(void) { @@ -427,10 +441,15 @@ ao_lisp_collect(void) int moved; struct ao_lisp_record *mark_record = NULL, *move_record = NULL; - ++dbg_collects; - MDBG_MOVE("collect %d\n", dbg_collects); + MDBG_MOVE("collect %d\n", ao_lisp_collects); marked = moved = 0; #endif + + ++ao_lisp_collects; + + /* Clear references to all caches */ + for (i = 0; i < (int) AO_LISP_CACHE; i++) + *ao_lisp_cache[i] = NULL; chunk_low = 0; top = 0; for (;;) { @@ -462,8 +481,10 @@ ao_lisp_collect(void) if (ao_lisp_chunk[i].old_addr > top) break; +#if DBG_MEM if (ao_lisp_chunk[i].old_addr != top) ao_lisp_abort(); +#endif top += size; MDBG_MOVE("chunk %d %d not moving\n", @@ -585,8 +606,10 @@ ao_lisp_poly_mark(ao_poly p, uint8_t do_note_cons) if (type == AO_LISP_OTHER) { type = ao_lisp_other_type(ao_lisp_poly_other(p)); +#if DBG_MEM if (type <= AO_LISP_OTHER || AO_LISP_NUM_TYPE <= type) ao_lisp_abort(); +#endif } lisp_type = ao_lisp_types[ao_lisp_poly_type(p)]; @@ -622,6 +645,8 @@ ao_lisp_move_memory(const struct ao_lisp_type *type, void **ref) if (!AO_LISP_IS_POOL(addr)) return 1; + (void) type; + MDBG_MOVE("move memory %d\n", MDBG_OFFSET(addr)); addr = move_map(addr); if (addr != *ref) { @@ -682,8 +707,10 @@ ao_lisp_poly_move(ao_poly *ref, uint8_t do_note_cons) if (type == AO_LISP_OTHER) { type = ao_lisp_other_type(move_map(ao_lisp_poly_other(p))); +#if DBG_MEM if (type <= AO_LISP_OTHER || AO_LISP_NUM_TYPE <= type) ao_lisp_abort(); +#endif } lisp_type = ao_lisp_types[type]; @@ -795,8 +822,6 @@ ao_lisp_alloc(int size) void ao_lisp_cons_stash(int id, struct ao_lisp_cons *cons) { - if (save_cons[id] != NULL) - ao_lisp_abort(); save_cons[id] = cons; } @@ -811,8 +836,6 @@ ao_lisp_cons_fetch(int id) void ao_lisp_string_stash(int id, char *string) { - if (save_cons[id] != NULL) - ao_lisp_abort(); save_string[id] = string; } diff --git a/src/lisp/ao_lisp_save.c b/src/lisp/ao_lisp_save.c index 030846b7..d5f28e7d 100644 --- a/src/lisp/ao_lisp_save.c +++ b/src/lisp/ao_lisp_save.c @@ -27,7 +27,7 @@ ao_lisp_save(struct ao_lisp_cons *cons) os->atoms = ao_lisp_atom_poly(ao_lisp_atoms); os->globals = ao_lisp_frame_poly(ao_lisp_frame_global); os->const_checksum = ao_lisp_const_checksum; - os->const_checksum_inv = ~ao_lisp_const_checksum; + os->const_checksum_inv = (uint16_t) ~ao_lisp_const_checksum; if (ao_lisp_os_save()) return _ao_lisp_atom_t; -- cgit v1.2.3 From 74ff0c6fd6c41cdaa054dcdb3d05c7d333bc24ff Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 14 Nov 2016 21:27:03 -0800 Subject: altos/lisp: Show number of collect calls in ao_lisp_test This helps tune the allocator Signed-off-by: Keith Packard --- src/test/ao_lisp_test.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/test/ao_lisp_test.c b/src/test/ao_lisp_test.c index 648d1abe..bbaa3f9d 100644 --- a/src/test/ao_lisp_test.c +++ b/src/test/ao_lisp_test.c @@ -101,4 +101,5 @@ main (int argc, char **argv) ao_lisp_file = NULL; } ao_lisp_read_eval_print(); + printf ("%d collects\n", ao_lisp_collects); } -- cgit v1.2.3 From 13a4d451b903d08e52005bcf531efa8de351bf2b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 14 Nov 2016 21:27:41 -0800 Subject: altos/lisp: Improve hanoi demo Repaint in place, without first clearing. This makes the updates a lot clealyer looking. Signed-off-by: Keith Packard --- src/test/hanoi.lisp | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/test/hanoi.lisp b/src/test/hanoi.lisp index 2b614829..0c4bfca5 100644 --- a/src/test/hanoi.lisp +++ b/src/test/hanoi.lisp @@ -8,6 +8,8 @@ (setq stack '("*" "**" "***" "****" "*****" "******" "*******")) +(setq top (+ (length stack) 3)) + (setq stacks nil) (defun display-string (x y str) @@ -15,19 +17,20 @@ (patom str) ) -(defun display-stack (x y stack) - (cond (stack (progn - (display-string x y (car stack)) - (display-stack x (1+ y) (cdr stack))))) - ) - -(defun clear-stack (x y) - (cond ((> y 0) (progn - (move-to x y) - (patom " ") - (clear-stack x (1- y)) - ) +(defun display-stack (x y clear stack) + (cond ((= 0 clear) + (cond (stack (progn + (display-string x y (car stack)) + (display-stack x (1+ y) 0 (cdr stack)) + ) + ) + ) ) + (t (progn + (display-string x y " ") + (display-stack x (1+ y) (1- clear) stack) + ) + ) ) ) @@ -43,15 +46,14 @@ (defun display-stacks (x y stacks) (cond (stacks (progn - (clear-stack x 20) - (display-stack x (stack-pos y (car stacks)) (car stacks)) + (display-stack x 0 (stack-pos y (car stacks)) (car stacks)) (display-stacks (+ x 20) y (cdr stacks))) ) ) ) (defun display () - (display-stacks 0 20 stacks) + (display-stacks 0 top stacks) (move-to 1 21) (flush) ) -- cgit v1.2.3 From b3b5bd2c14cfcde6c551a87ee6da08a53f1e4bc6 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 14 Nov 2016 23:04:05 -0800 Subject: altos/lisp: Add license to hanoi demo Signed-off-by: Keith Packard --- src/test/hanoi.lisp | 68 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/test/hanoi.lisp b/src/test/hanoi.lisp index 0c4bfca5..b84b8174 100644 --- a/src/test/hanoi.lisp +++ b/src/test/hanoi.lisp @@ -1,3 +1,22 @@ +; +; Towers of Hanoi +; +; Copyright © 2016 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 2 of the License, or +; (at your option) any later version. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; + + +; ANSI control sequences + (defun move-to (col row) (patom "\033[" row ";" col "H" nil) ) @@ -6,16 +25,25 @@ (patom "\033[2J" nil) ) +(defun display-string (x y str) + (move-to x y) + (patom str) + ) + +; Here's the pieces to display + (setq stack '("*" "**" "***" "****" "*****" "******" "*******")) (setq top (+ (length stack) 3)) +; +; Here's all of the stacks of pieces +; This is generated when the program is run +; (setq stacks nil) -(defun display-string (x y str) - (move-to x y) - (patom str) - ) +; Display one stack, clearing any +; space above it (defun display-stack (x y clear stack) (cond ((= 0 clear) @@ -34,16 +62,23 @@ ) ) +; This should probably be included in the rom image... + (defun length (list) (cond (list (1+ (length (cdr list)))) (0) ) ) +; Position of the top of the stack on the screen +; Shorter stacks start further down the screen + (defun stack-pos (y stack) (- y (length stack)) ) +; Display all of the stacks, spaced 20 columns apart + (defun display-stacks (x y stacks) (cond (stacks (progn (display-stack x 0 (stack-pos y (car stacks)) (car stacks)) @@ -52,21 +87,27 @@ ) ) +; Display all of the stacks, then move the cursor +; out of the way and flush the output + (defun display () (display-stacks 0 top stacks) (move-to 1 21) (flush) ) -(defun length (l) - (cond (l (1+ (length (cdr l)))) (0)) - ) +; Reset stacks to the starting state, with +; all of the pieces in the first stack and the +; other two empty (defun reset-stacks () (setq stacks (list stack nil nil)) (length stack) ) +; more functions which could usefully +; be in the rom image + (defun min (a b) (cond ((< a b) a) (b) @@ -79,12 +120,18 @@ ) ) +; Replace a stack in the list of stacks +; with a new value + (defun replace (list pos member) (cond ((= pos 0) (cons member (cdr list))) ((cons (car list) (replace (cdr list) (1- pos) member))) ) ) +; Move a piece from the top of one stack +; to the top of another + (defun move-piece (from to) (let ((from-stack (nth stacks from)) (to-stack (nth stacks to)) @@ -98,6 +145,8 @@ ) ) +; The implementation of the game + (defun _hanoi (n from to use) (cond ((= 1 n) (progn @@ -114,6 +163,11 @@ ) ) +; A pretty interface which +; resets the state of the game, +; clears the screen and runs +; the program + (defun hanoi () (setq len (reset-stacks)) (clear) -- cgit v1.2.3 From 974717eb9dad105c9897ee24f953d98d57eaec77 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 15 Nov 2016 09:55:22 -0800 Subject: altos/lisp: Evaluate macros once, then smash them into place This assumes that macros are all pure functions, which should be true for syntactic macros. Signed-off-by: Keith Packard --- src/lisp/Makefile | 5 +- src/lisp/ao_lisp.h | 17 +-- src/lisp/ao_lisp_builtin.c | 2 + src/lisp/ao_lisp_const.lisp | 24 ++-- src/lisp/ao_lisp_eval.c | 23 +++- src/lisp/ao_lisp_make_const.c | 263 ++++++++++++++++++++++++++++++++---------- src/lisp/ao_lisp_os.h | 7 +- 7 files changed, 253 insertions(+), 88 deletions(-) (limited to 'src') diff --git a/src/lisp/Makefile b/src/lisp/Makefile index dac11f66..b06e10dd 100644 --- a/src/lisp/Makefile +++ b/src/lisp/Makefile @@ -4,7 +4,7 @@ clean: rm -f ao_lisp_const.h $(OBJS) ao_lisp_make_const ao_lisp_const.h: ao_lisp_const.lisp ao_lisp_make_const - ./ao_lisp_make_const < ao_lisp_const.lisp > $@ + ./ao_lisp_make_const -o $@ ao_lisp_const.lisp SRCS=\ ao_lisp_make_const.c\ @@ -25,10 +25,11 @@ SRCS=\ OBJS=$(SRCS:.c=.o) -CFLAGS=-DAO_LISP_MAKE_CONST -O0 -g -I. +CFLAGS=-DAO_LISP_MAKE_CONST -O0 -g -I. -Wall -Wextra HDRS=\ ao_lisp.h \ + ao_lisp_os.h \ ao_lisp_read.h ao_lisp_make_const: $(OBJS) diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index efd13cf5..2db4914f 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -173,14 +173,15 @@ ao_lisp_frame_poly(struct ao_lisp_frame *frame) { enum eval_state { eval_sexpr, /* Evaluate an sexpr */ - eval_val, - eval_formal, - eval_exec, - eval_cond, - eval_cond_test, - eval_progn, - eval_while, - eval_while_test, + eval_val, /* Value computed */ + eval_formal, /* Formal computed */ + eval_exec, /* Start a lambda evaluation */ + eval_cond, /* Start next cond clause */ + eval_cond_test, /* Check cond condition */ + eval_progn, /* Start next progn entry */ + eval_while, /* Start while condition */ + eval_while_test, /* Check while condition */ + eval_macro, /* Finished with macro generation */ }; struct ao_lisp_stack { diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index ebc69f77..e4b7ef52 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -41,9 +41,11 @@ const struct ao_lisp_type ao_lisp_builtin_type = { #ifdef AO_LISP_MAKE_CONST char *ao_lisp_builtin_name(enum ao_lisp_builtin_id b) { + (void) b; return "???"; } char *ao_lisp_args_name(uint8_t args) { + (void) args; return "???"; } #else diff --git a/src/lisp/ao_lisp_const.lisp b/src/lisp/ao_lisp_const.lisp index c6f50e34..9d8af588 100644 --- a/src/lisp/ao_lisp_const.lisp +++ b/src/lisp/ao_lisp_const.lisp @@ -9,10 +9,6 @@ ;(setq progn (lexpr (l) (last l))) - ; simple math operators - -(setq 1+ (lambda (x) (+ x 1))) -(setq 1- (lambda (x) (- x 1))) ; ; Define a variable without returning the value @@ -64,7 +60,7 @@ ; make the list of names in the let ; - (set 'make-names (lambda (vars) + (setq make-names (lambda (vars) (cond (vars (cons (car (car vars)) (make-names (cdr vars)))) @@ -77,7 +73,7 @@ ; pre-pended to the ; expressions to evaluate ; - (set 'make-exprs (lambda (vars exprs) + (setq make-exprs (lambda (vars exprs) (progn (cond (vars (cons (list set @@ -94,13 +90,13 @@ ) ) ) - (set 'exprs (make-exprs vars exprs)) + (setq exprs (make-exprs vars exprs)) ; ; the parameters to the lambda is a list ; of nils of the right length ; - (set 'make-nils (lambda (vars) + (setq make-nils (lambda (vars) (cond (vars (cons nil (make-nils (cdr vars)))) ) ) @@ -108,7 +104,6 @@ ; ; build the lambda. ; - (set 'last-let-value (cons (list 'lambda @@ -120,8 +115,6 @@ (make-nils vars) ) ) - ) - ) (car let-param) (cdr let-param) @@ -158,3 +151,12 @@ ) ) ) + + ; simple math operators + ; + ; Do these last to run defun + ; at least once so the let macro + ; is resolved + +(defun 1+ (x) (+ x 1)) +(defun 1- (x) (- x 1)) diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index 5cc1b75a..3af56796 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -298,7 +298,7 @@ ao_lisp_eval_formal(void) break; case AO_LISP_FUNC_MACRO: /* Evaluate the result once more */ - ao_lisp_stack->state = eval_sexpr; + ao_lisp_stack->state = eval_macro; if (!ao_lisp_stack_push()) return 0; @@ -308,7 +308,6 @@ ao_lisp_eval_formal(void) prev = ao_lisp_poly_stack(ao_lisp_stack->prev); ao_lisp_stack->state = eval_sexpr; ao_lisp_stack->sexprs = prev->sexprs; - prev->sexprs = AO_LISP_NIL; DBGI(".. start macro\n"); DBGI(".. sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); @@ -555,6 +554,25 @@ ao_lisp_eval_while_test(void) return 1; } +/* + * Replace the original sexpr with the macro expansion, then + * execute that + */ +static int +ao_lisp_eval_macro(void) +{ + DBGI("macro: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); + + if (ao_lisp_poly_type(ao_lisp_v) == AO_LISP_CONS) { + *ao_lisp_poly_cons(ao_lisp_stack->sexprs) = *ao_lisp_poly_cons(ao_lisp_v); + ao_lisp_v = ao_lisp_stack->sexprs; + DBGI("sexprs rewritten to: "); DBG_POLY(ao_lisp_v); DBG("\n"); + } + ao_lisp_stack->sexprs = AO_LISP_NIL; + ao_lisp_stack->state = eval_sexpr; + return 1; +} + static int (*const evals[])(void) = { [eval_sexpr] = ao_lisp_eval_sexpr, [eval_val] = ao_lisp_eval_val, @@ -565,6 +583,7 @@ static int (*const evals[])(void) = { [eval_progn] = ao_lisp_eval_progn, [eval_while] = ao_lisp_eval_while, [eval_while_test] = ao_lisp_eval_while_test, + [eval_macro] = ao_lisp_eval_macro, }; /* diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index 178b041e..ae53bd35 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -15,6 +15,8 @@ #include "ao_lisp.h" #include #include +#include +#include static struct ao_lisp_builtin * ao_lisp_make_builtin(enum ao_lisp_builtin_id func, int args) { @@ -33,42 +35,42 @@ struct builtin_func { }; struct builtin_func funcs[] = { - "eval", AO_LISP_FUNC_F_LAMBDA, builtin_eval, - "read", AO_LISP_FUNC_F_LAMBDA, builtin_read, - "lambda", AO_LISP_FUNC_NLAMBDA, builtin_lambda, - "lexpr", AO_LISP_FUNC_NLAMBDA, builtin_lexpr, - "nlambda", AO_LISP_FUNC_NLAMBDA, builtin_nlambda, - "macro", AO_LISP_FUNC_NLAMBDA, builtin_macro, - "car", AO_LISP_FUNC_F_LAMBDA, builtin_car, - "cdr", AO_LISP_FUNC_F_LAMBDA, builtin_cdr, - "cons", AO_LISP_FUNC_F_LAMBDA, builtin_cons, - "last", AO_LISP_FUNC_F_LAMBDA, builtin_last, - "length", AO_LISP_FUNC_F_LAMBDA, builtin_length, - "quote", AO_LISP_FUNC_NLAMBDA, builtin_quote, - "set", AO_LISP_FUNC_F_LAMBDA, builtin_set, - "setq", AO_LISP_FUNC_MACRO, builtin_setq, - "cond", AO_LISP_FUNC_NLAMBDA, builtin_cond, - "progn", AO_LISP_FUNC_NLAMBDA, builtin_progn, - "while", AO_LISP_FUNC_NLAMBDA, builtin_while, - "print", AO_LISP_FUNC_F_LEXPR, builtin_print, - "patom", AO_LISP_FUNC_F_LEXPR, builtin_patom, - "+", AO_LISP_FUNC_F_LEXPR, builtin_plus, - "-", AO_LISP_FUNC_F_LEXPR, builtin_minus, - "*", AO_LISP_FUNC_F_LEXPR, builtin_times, - "/", AO_LISP_FUNC_F_LEXPR, builtin_divide, - "%", AO_LISP_FUNC_F_LEXPR, builtin_mod, - "=", AO_LISP_FUNC_F_LEXPR, builtin_equal, - "<", AO_LISP_FUNC_F_LEXPR, builtin_less, - ">", AO_LISP_FUNC_F_LEXPR, builtin_greater, - "<=", AO_LISP_FUNC_F_LEXPR, builtin_less_equal, - ">=", AO_LISP_FUNC_F_LEXPR, builtin_greater_equal, - "pack", AO_LISP_FUNC_F_LAMBDA, builtin_pack, - "unpack", AO_LISP_FUNC_F_LAMBDA, builtin_unpack, - "flush", AO_LISP_FUNC_F_LAMBDA, builtin_flush, - "delay", AO_LISP_FUNC_F_LAMBDA, builtin_delay, - "led", AO_LISP_FUNC_F_LEXPR, builtin_led, - "save", AO_LISP_FUNC_F_LAMBDA, builtin_save, - "restore", AO_LISP_FUNC_F_LAMBDA, builtin_restore, + { .name = "eval", .args = AO_LISP_FUNC_F_LAMBDA, .func = builtin_eval }, + { .name = "read", .args = AO_LISP_FUNC_F_LAMBDA, .func = builtin_read }, + { .name = "lambda", .args = AO_LISP_FUNC_NLAMBDA, .func = builtin_lambda }, + { .name = "lexpr", .args = AO_LISP_FUNC_NLAMBDA, .func = builtin_lexpr }, + { .name = "nlambda", .args = AO_LISP_FUNC_NLAMBDA, .func = builtin_nlambda }, + { .name = "macro", .args = AO_LISP_FUNC_NLAMBDA, .func = builtin_macro }, + { .name = "car", .args = AO_LISP_FUNC_F_LAMBDA, .func = builtin_car }, + { .name = "cdr", .args = AO_LISP_FUNC_F_LAMBDA, .func = builtin_cdr }, + { .name = "cons", .args = AO_LISP_FUNC_F_LAMBDA, .func = builtin_cons }, + { .name = "last", .args = AO_LISP_FUNC_F_LAMBDA, .func = builtin_last }, + { .name = "length", .args = AO_LISP_FUNC_F_LAMBDA, .func = builtin_length }, + { .name = "quote", .args = AO_LISP_FUNC_NLAMBDA, .func = builtin_quote }, + { .name = "set", .args = AO_LISP_FUNC_F_LAMBDA, .func = builtin_set }, + { .name = "setq", .args = AO_LISP_FUNC_MACRO, .func = builtin_setq }, + { .name = "cond", .args = AO_LISP_FUNC_NLAMBDA, .func = builtin_cond }, + { .name = "progn", .args = AO_LISP_FUNC_NLAMBDA, .func = builtin_progn }, + { .name = "while", .args = AO_LISP_FUNC_NLAMBDA, .func = builtin_while }, + { .name = "print", .args = AO_LISP_FUNC_F_LEXPR, .func = builtin_print }, + { .name = "patom", .args = AO_LISP_FUNC_F_LEXPR, .func = builtin_patom }, + { .name = "+", .args = AO_LISP_FUNC_F_LEXPR, .func = builtin_plus }, + { .name = "-", .args = AO_LISP_FUNC_F_LEXPR, .func = builtin_minus }, + { .name = "*", .args = AO_LISP_FUNC_F_LEXPR, .func = builtin_times }, + { .name = "/", .args = AO_LISP_FUNC_F_LEXPR, .func = builtin_divide }, + { .name = "%", .args = AO_LISP_FUNC_F_LEXPR, .func = builtin_mod }, + { .name = "=", .args = AO_LISP_FUNC_F_LEXPR, .func = builtin_equal }, + { .name = "<", .args = AO_LISP_FUNC_F_LEXPR, .func = builtin_less }, + { .name = ">", .args = AO_LISP_FUNC_F_LEXPR, .func = builtin_greater }, + { .name = "<=", .args = AO_LISP_FUNC_F_LEXPR, .func = builtin_less_equal }, + { .name = ">=", .args = AO_LISP_FUNC_F_LEXPR, .func = builtin_greater_equal }, + { .name = "pack", .args = AO_LISP_FUNC_F_LAMBDA, .func = builtin_pack }, + { .name = "unpack", .args = AO_LISP_FUNC_F_LAMBDA, .func = builtin_unpack }, + { .name = "flush", .args = AO_LISP_FUNC_F_LAMBDA, .func = builtin_flush }, + { .name = "delay", .args = AO_LISP_FUNC_F_LAMBDA, .func = builtin_delay }, + { .name = "led", .args = AO_LISP_FUNC_F_LEXPR, .func = builtin_led }, + { .name = "save", .args = AO_LISP_FUNC_F_LAMBDA, .func = builtin_save }, + { .name = "restore", .args = AO_LISP_FUNC_F_LAMBDA, .func = builtin_restore }, }; #define N_FUNC (sizeof funcs / sizeof funcs[0]) @@ -113,18 +115,127 @@ ao_fec_crc(const uint8_t *bytes, uint8_t len) return crc; } +int +ao_is_macro(ao_poly p) +{ + struct ao_lisp_builtin *builtin; + struct ao_lisp_lambda *lambda; + +// printf ("macro scanning "); ao_lisp_poly_print(p); printf("\n"); + switch (ao_lisp_poly_type(p)) { + case AO_LISP_ATOM: + return ao_is_macro(ao_lisp_atom_get(p)); + case AO_LISP_BUILTIN: + builtin = ao_lisp_poly_builtin(p); + if ((builtin->args & AO_LISP_FUNC_MASK) == AO_LISP_FUNC_MACRO) + return 1; + return 0; + case AO_LISP_LAMBDA: + lambda = ao_lisp_poly_lambda(p); + if (lambda->args == AO_LISP_FUNC_MACRO) + return 1; + return 0; + default: + return 0; + } +} + +ao_poly +ao_has_macro(ao_poly p) +{ + struct ao_lisp_cons *cons; + struct ao_lisp_lambda *lambda; + ao_poly m; + + if (p == AO_LISP_NIL) + return AO_LISP_NIL; + + switch (ao_lisp_poly_type(p)) { + case AO_LISP_LAMBDA: + lambda = ao_lisp_poly_lambda(p); + return ao_has_macro(lambda->code); + case AO_LISP_CONS: + cons = ao_lisp_poly_cons(p); + if (ao_is_macro(cons->car)) + return cons->car; + + cons = ao_lisp_poly_cons(cons->cdr); + while (cons) { + m = ao_has_macro(cons->car); + if (m) + return m; + cons = ao_lisp_poly_cons(cons->cdr); + } + return AO_LISP_NIL; + + default: + return AO_LISP_NIL; + } +} + +int +ao_lisp_read_eval_abort(void) +{ + ao_poly in, out = AO_LISP_NIL; + for(;;) { + in = ao_lisp_read(); + if (in == _ao_lisp_atom_eof) + break; + out = ao_lisp_eval(in); + if (ao_lisp_exception) + return 0; + ao_lisp_poly_print(out); + putchar ('\n'); + } + return 1; +} + +static FILE *in; +static FILE *out; + +int +ao_lisp_getc(void) +{ + return getc(in); +} + +static const struct option options[] = { + { .name = "out", .has_arg = 1, .val = 'o' }, + { 0, 0, 0, 0 } +}; + +static void usage(char *program) +{ + fprintf(stderr, "usage: %s [--out=] [input]\n", program); + exit(1); +} + int main(int argc, char **argv) { - int f, o, i; - ao_poly sexpr, val; + int f, o; + ao_poly val; struct ao_lisp_atom *a; struct ao_lisp_builtin *b; int in_atom; + char *out_name; + int c; + + in = stdin; + out = stdout; + + while ((c = getopt_long(argc, argv, "o:", options, NULL)) != -1) { + switch (c) { + case 'o': + out_name = optarg; + break; + default: + usage(argv[0]); + break; + } + } - printf("/*\n"); - printf(" * Generated file, do not edit\n"); - for (f = 0; f < N_FUNC; f++) { + for (f = 0; f < (int) N_FUNC; f++) { b = ao_lisp_make_builtin(funcs[f].func, funcs[f].args); a = ao_lisp_atom_intern(funcs[f].name); ao_lisp_atom_set(ao_lisp_atom_poly(a), @@ -143,47 +254,79 @@ main(int argc, char **argv) ao_lisp_atom_set(ao_lisp_atom_poly(a), ao_lisp_atom_poly(a)); - ao_lisp_read_eval_print(); + if (argv[optind]){ + in = fopen(argv[optind], "r"); + if (!in) { + perror(argv[optind]); + exit(1); + } + } + if (!ao_lisp_read_eval_abort()) { + fprintf(stderr, "eval failed\n"); + exit(1); + } /* Reduce to referenced values */ ao_lisp_collect(); - printf(" */\n"); - printf("#define AO_LISP_POOL_CONST %d\n", ao_lisp_top); - printf("extern const uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4)));\n"); - printf("#define ao_builtin_atoms 0x%04x\n", ao_lisp_atom_poly(ao_lisp_atoms)); - printf("#define ao_builtin_frame 0x%04x\n", ao_lisp_frame_poly(ao_lisp_frame_global)); - printf("#define ao_lisp_const_checksum ((uint16_t) 0x%04x)\n", ao_fec_crc(ao_lisp_const, ao_lisp_top)); + for (f = 0; f < ao_lisp_frame_global->num; f++) { + val = ao_has_macro(ao_lisp_frame_global->vals[f].val); + if (val != AO_LISP_NIL) { + printf("error: function %s contains unresolved macro: ", + ao_lisp_poly_atom(ao_lisp_frame_global->vals[f].atom)->name); + ao_lisp_poly_print(val); + printf(stderr, "\n"); + exit(1); + } + } + + if (out_name) { + out = fopen(out_name, "w"); + if (!out) { + perror(out_name); + exit(1); + } + } + + fprintf(out, "/* Generated file, do not edit */\n\n"); + + fprintf(out, "#define AO_LISP_POOL_CONST %d\n", ao_lisp_top); + fprintf(out, "extern const uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4)));\n"); + fprintf(out, "#define ao_builtin_atoms 0x%04x\n", ao_lisp_atom_poly(ao_lisp_atoms)); + fprintf(out, "#define ao_builtin_frame 0x%04x\n", ao_lisp_frame_poly(ao_lisp_frame_global)); + fprintf(out, "#define ao_lisp_const_checksum ((uint16_t) 0x%04x)\n", ao_fec_crc(ao_lisp_const, ao_lisp_top)); + for (a = ao_lisp_atoms; a; a = ao_lisp_poly_atom(a->next)) { char *n = a->name, c; - printf ("#define _ao_lisp_atom_"); + fprintf(out, "#define _ao_lisp_atom_"); while ((c = *n++)) { if (isalnum(c)) - printf("%c", c); + fprintf(out, "%c", c); else - printf("%02x", c); + fprintf(out, "%02x", c); } - printf(" 0x%04x\n", ao_lisp_atom_poly(a)); + fprintf(out, " 0x%04x\n", ao_lisp_atom_poly(a)); } - printf("#ifdef AO_LISP_CONST_BITS\n"); - printf("const uint8_t ao_lisp_const[] = {"); + fprintf(out, "#ifdef AO_LISP_CONST_BITS\n"); + fprintf(out, "const uint8_t ao_lisp_const[] = {"); for (o = 0; o < ao_lisp_top; o++) { uint8_t c; if ((o & 0xf) == 0) - printf("\n\t"); + fprintf(out, "\n\t"); else - printf(" "); + fprintf(out, " "); c = ao_lisp_const[o]; if (!in_atom) in_atom = is_atom(o); if (in_atom) { - printf (" '%c',", c); + fprintf(out, " '%c',", c); in_atom--; } else { - printf("0x%02x,", c); + fprintf(out, "0x%02x,", c); } } - printf("\n};\n"); - printf("#endif /* AO_LISP_CONST_BITS */\n"); + fprintf(out, "\n};\n"); + fprintf(out, "#endif /* AO_LISP_CONST_BITS */\n"); + exit(0); } diff --git a/src/lisp/ao_lisp_os.h b/src/lisp/ao_lisp_os.h index b7bf7a2c..5fa3686b 100644 --- a/src/lisp/ao_lisp_os.h +++ b/src/lisp/ao_lisp_os.h @@ -22,13 +22,10 @@ #include #include -static inline int -ao_lisp_getc() { - return getchar(); -} +extern int ao_lisp_getc(void); static inline void -ao_lisp_os_flush() { +ao_lisp_os_flush(void) { fflush(stdout); } -- cgit v1.2.3 From 41175ff82bc0e35c99c60b49aa62944a12917157 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 15 Nov 2016 10:18:12 -0800 Subject: altos/lisp: Get lambdakey and nucleo-32 building again Remove exti from the build list to make things fit. Signed-off-by: Keith Packard --- src/lambdakey-v1.0/Makefile | 3 +-- src/lisp/ao_lisp_builtin.c | 1 + src/nucleao-32/Makefile | 9 +++++++-- src/nucleao-32/ao_nucleo.c | 29 ----------------------------- src/nucleao-32/ao_pins.h | 5 +++-- 5 files changed, 12 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/lambdakey-v1.0/Makefile b/src/lambdakey-v1.0/Makefile index c71e1ab5..7f71761b 100644 --- a/src/lambdakey-v1.0/Makefile +++ b/src/lambdakey-v1.0/Makefile @@ -50,8 +50,7 @@ ALTOS_SRC = \ ao_lisp_error.c \ ao_lisp_lambda.c \ ao_lisp_save.c \ - ao_lisp_os_save.c \ - ao_exti_stm.c + ao_lisp_os_save.c PRODUCT=LambdaKey-v1.0 PRODUCT_DEF=-DLAMBDAKEY diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index e4b7ef52..b808cbc5 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -106,6 +106,7 @@ static const ao_poly ao_lisp_args_atoms[] = { char * ao_lisp_args_name(uint8_t args) { + args &= AO_LISP_FUNC_MASK; if (args < sizeof ao_lisp_args_atoms / sizeof ao_lisp_args_atoms[0]) return ao_lisp_poly_atom(ao_lisp_args_atoms[args])->name; return "(unknown)"; diff --git a/src/nucleao-32/Makefile b/src/nucleao-32/Makefile index 388e581c..57fb4cde 100644 --- a/src/nucleao-32/Makefile +++ b/src/nucleao-32/Makefile @@ -34,6 +34,7 @@ ALTOS_SRC = \ ao_mutex.c \ ao_usb_stm.c \ ao_serial_stm.c \ + ao_flash_stm.c \ ao_lisp_lex.c \ ao_lisp_mem.c \ ao_lisp_cons.c \ @@ -41,13 +42,15 @@ ALTOS_SRC = \ ao_lisp_string.c \ ao_lisp_atom.c \ ao_lisp_int.c \ - ao_lisp_prim.c \ + ao_lisp_poly.c \ ao_lisp_builtin.c \ ao_lisp_read.c \ ao_lisp_rep.c \ ao_lisp_frame.c \ ao_lisp_error.c \ - ao_exti_stm.c + ao_lisp_lambda.c \ + ao_lisp_save.c \ + ao_lisp_os_save.c PRODUCT=Nucleo-32 PRODUCT_DEF=-DNUCLEO @@ -55,6 +58,8 @@ IDPRODUCT=0x000a CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -Os -g +LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Tload.ld + PROGNAME=nucleo-32 PROG=$(PROGNAME)-$(VERSION).elf HEX=$(PROGNAME)-$(VERSION).ihx diff --git a/src/nucleao-32/ao_nucleo.c b/src/nucleao-32/ao_nucleo.c index 113e2399..3e448865 100644 --- a/src/nucleao-32/ao_nucleo.c +++ b/src/nucleao-32/ao_nucleo.c @@ -15,44 +15,15 @@ #include #include -static uint16_t blink_delay, blink_running; - -static void blink(void) { - blink_running = 1; - while (blink_delay) { - ao_led_on(AO_LED_GREEN); - ao_delay(blink_delay); - ao_led_off(AO_LED_GREEN); - ao_delay(blink_delay); - } - blink_running = 0; - ao_wakeup(&blink_running); - ao_exit(); -} - -struct ao_task blink_task; - -static void blink_cmd() { - ao_cmd_decimal(); - blink_delay = ao_cmd_lex_i; - if (blink_delay && !blink_running) - ao_add_task(&blink_task, blink, "blink"); - if (!blink_delay) - while (blink_running) - ao_sleep(&blink_running); -} - static void lisp_cmd() { ao_lisp_read_eval_print(); } static const struct ao_cmds blink_cmds[] = { - { blink_cmd, "b \0Blink the green LED" }, { lisp_cmd, "l\0Run lisp interpreter" }, { 0, 0 } }; - void main(void) { ao_led_init(LEDS_AVAILABLE); diff --git a/src/nucleao-32/ao_pins.h b/src/nucleao-32/ao_pins.h index 092d347c..e631db7b 100644 --- a/src/nucleao-32/ao_pins.h +++ b/src/nucleao-32/ao_pins.h @@ -25,8 +25,9 @@ #define AO_LED_GREEN (1 << LED_PIN_GREEN) #define AO_LED_PANIC AO_LED_GREEN #define AO_CMD_LEN 128 -#define AO_LISP_POOL 1024 -#define AO_STACK_SIZE 1536 +#define AO_LISP_POOL_TOTAL 3072 +#define AO_LISP_SAVE 1 +#define AO_STACK_SIZE 1024 #define LEDS_AVAILABLE (AO_LED_GREEN) -- cgit v1.2.3 From 994adc7a47cbf3cbf6041eca7430273f8018de08 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 15 Nov 2016 10:32:36 -0800 Subject: altos/lisp: remove duplicate 'length' lambda from hanoi example This function is now a builtin. Signed-off-by: Keith Packard --- src/lambdakey-v1.0/Makefile | 1 + src/test/hanoi.lisp | 8 -------- 2 files changed, 1 insertion(+), 8 deletions(-) (limited to 'src') diff --git a/src/lambdakey-v1.0/Makefile b/src/lambdakey-v1.0/Makefile index 7f71761b..feadfa91 100644 --- a/src/lambdakey-v1.0/Makefile +++ b/src/lambdakey-v1.0/Makefile @@ -15,6 +15,7 @@ INC = \ ao_task.h \ ao_lisp.h \ ao_lisp_const.h \ + ao_lisp_os.h \ stm32f0.h \ Makefile diff --git a/src/test/hanoi.lisp b/src/test/hanoi.lisp index b84b8174..66a8d04b 100644 --- a/src/test/hanoi.lisp +++ b/src/test/hanoi.lisp @@ -62,14 +62,6 @@ ) ) -; This should probably be included in the rom image... - -(defun length (list) - (cond (list (1+ (length (cdr list)))) - (0) - ) - ) - ; Position of the top of the stack on the screen ; Shorter stacks start further down the screen -- cgit v1.2.3 From 881161fe1c5fb0e2b1220c30572eb2c45bedbafe Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 15 Nov 2016 20:18:59 -0800 Subject: altos/lisp: re-use small frames This saves a pile more use of the allocator by noting when frames have not been referenced from another frame and freeing them when they go out of scope. Frames with references are left to the allocator to deal with. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 37 +++++++++++++++++-- src/lisp/ao_lisp_atom.c | 4 +-- src/lisp/ao_lisp_error.c | 6 ++-- src/lisp/ao_lisp_eval.c | 6 +++- src/lisp/ao_lisp_frame.c | 91 +++++++++++++++++++++++++++++++---------------- src/lisp/ao_lisp_lambda.c | 4 +-- src/lisp/ao_lisp_mem.c | 8 +++++ 7 files changed, 116 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 2db4914f..bcb0a17f 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -156,13 +156,33 @@ struct ao_lisp_val { struct ao_lisp_frame { uint8_t type; - uint8_t num; - ao_poly next; + uint8_t _num; + ao_poly prev; struct ao_lisp_val vals[]; }; +#define AO_LISP_FRAME_NUM_MASK 0x7f + +/* Set when the frame escapes the lambda */ +#define AO_LISP_FRAME_MARK 0x80 + +static inline int ao_lisp_frame_num(struct ao_lisp_frame *f) { + if (f->_num == 0xff) + ao_lisp_abort(); + return f->_num & AO_LISP_FRAME_NUM_MASK; +} + +static inline int ao_lisp_frame_marked(struct ao_lisp_frame *f) { + if (f->_num == 0xff) + ao_lisp_abort(); + return f->_num & AO_LISP_FRAME_MARK; +} + static inline struct ao_lisp_frame * ao_lisp_poly_frame(ao_poly poly) { + struct ao_lisp_frame *frame = ao_lisp_ref(poly); + if (frame && frame->_num == 0xff) + ao_lisp_abort(); return ao_lisp_ref(poly); } @@ -500,6 +520,9 @@ ao_lisp_atom_print(ao_poly a); struct ao_lisp_atom * ao_lisp_atom_intern(char *name); +ao_poly * +ao_lisp_atom_ref(struct ao_lisp_frame *frame, ao_poly atom); + ao_poly ao_lisp_atom_get(ao_poly atom); @@ -574,12 +597,22 @@ ao_lisp_read_eval_print(void); /* frame */ extern const struct ao_lisp_type ao_lisp_frame_type; +#define AO_LISP_FRAME_FREE 4 + +extern struct ao_lisp_frame *ao_lisp_frame_free_list[AO_LISP_FRAME_FREE]; + +ao_poly +ao_lisp_frame_mark(struct ao_lisp_frame *frame); + ao_poly * ao_lisp_frame_ref(struct ao_lisp_frame *frame, ao_poly atom); struct ao_lisp_frame * ao_lisp_frame_new(int num); +void +ao_lisp_frame_free(struct ao_lisp_frame *frame); + int ao_lisp_frame_add(struct ao_lisp_frame **frame, ao_poly atom, ao_poly val); diff --git a/src/lisp/ao_lisp_atom.c b/src/lisp/ao_lisp_atom.c index 6705f140..8c9e8ed1 100644 --- a/src/lisp/ao_lisp_atom.c +++ b/src/lisp/ao_lisp_atom.c @@ -108,7 +108,7 @@ ao_lisp_atom_init(void) ao_lisp_frame_global = ao_lisp_frame_new(0); } -static ao_poly * +ao_poly * ao_lisp_atom_ref(struct ao_lisp_frame *frame, ao_poly atom) { ao_poly *ref; @@ -117,7 +117,7 @@ ao_lisp_atom_ref(struct ao_lisp_frame *frame, ao_poly atom) ref = ao_lisp_frame_ref(frame, atom); if (ref) return ref; - frame = ao_lisp_poly_frame(frame->next); + frame = ao_lisp_poly_frame(frame->prev); } if (ao_lisp_frame_global) { ref = ao_lisp_frame_ref(ao_lisp_frame_global, atom); diff --git a/src/lisp/ao_lisp_error.c b/src/lisp/ao_lisp_error.c index cfa78d22..2b15c418 100644 --- a/src/lisp/ao_lisp_error.c +++ b/src/lisp/ao_lisp_error.c @@ -49,7 +49,7 @@ ao_lisp_error_frame(int indent, char *name, struct ao_lisp_frame *frame) tabs(indent); printf ("%s{", name); if (frame) { - for (f = 0; f < frame->num; f++) { + for (f = 0; f < ao_lisp_frame_num(frame); f++) { if (f != 0) { tabs(indent); printf(" "); @@ -59,8 +59,8 @@ ao_lisp_error_frame(int indent, char *name, struct ao_lisp_frame *frame) ao_lisp_poly_print(frame->vals[f].val); printf("\n"); } - if (frame->next) - ao_lisp_error_frame(indent + 1, "next: ", ao_lisp_poly_frame(frame->next)); + if (frame->prev) + ao_lisp_error_frame(indent + 1, "prev: ", ao_lisp_poly_frame(frame->prev)); } tabs(indent); printf(" }\n"); diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index 3af56796..6f56a120 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -122,7 +122,8 @@ ao_lisp_stack_push(void) static void ao_lisp_stack_pop(void) { - ao_poly prev; + ao_poly prev; + struct ao_lisp_frame *prev_frame; if (!ao_lisp_stack) return; @@ -131,10 +132,13 @@ ao_lisp_stack_pop(void) ao_lisp_stack_free_list = ao_lisp_stack; ao_lisp_stack = ao_lisp_poly_stack(prev); + prev_frame = ao_lisp_frame_current; if (ao_lisp_stack) ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->frame); else ao_lisp_frame_current = NULL; + if (ao_lisp_frame_current != prev_frame) + ao_lisp_frame_free(prev_frame); DBG_OUT(); DBGI("stack pop\n"); DBG_FRAMES(); diff --git a/src/lisp/ao_lisp_frame.c b/src/lisp/ao_lisp_frame.c index e23a6413..052d27d7 100644 --- a/src/lisp/ao_lisp_frame.c +++ b/src/lisp/ao_lisp_frame.c @@ -24,7 +24,7 @@ static int frame_size(void *addr) { struct ao_lisp_frame *frame = addr; - return frame_num_size(frame->num); + return frame_num_size(ao_lisp_frame_num(frame)); } static void @@ -37,7 +37,7 @@ frame_mark(void *addr) MDBG_MOVE("frame mark %d\n", MDBG_OFFSET(frame)); if (!AO_LISP_IS_POOL(frame)) break; - for (f = 0; f < frame->num; f++) { + for (f = 0; f < ao_lisp_frame_num(frame); f++) { struct ao_lisp_val *v = &frame->vals[f]; ao_lisp_poly_mark(v->val, 0); @@ -46,7 +46,7 @@ frame_mark(void *addr) MDBG_OFFSET(ao_lisp_ref(v->atom)), MDBG_OFFSET(ao_lisp_ref(v->val)), f); } - frame = ao_lisp_poly_frame(frame->next); + frame = ao_lisp_poly_frame(frame->prev); MDBG_MOVE("frame next %d\n", MDBG_OFFSET(frame)); if (!frame) break; @@ -62,13 +62,13 @@ frame_move(void *addr) int f; for (;;) { - struct ao_lisp_frame *next; + struct ao_lisp_frame *prev; int ret; MDBG_MOVE("frame move %d\n", MDBG_OFFSET(frame)); if (!AO_LISP_IS_POOL(frame)) break; - for (f = 0; f < frame->num; f++) { + for (f = 0; f < ao_lisp_frame_num(frame); f++) { struct ao_lisp_val *v = &frame->vals[f]; ao_lisp_poly_move(&v->atom, 0); @@ -78,19 +78,19 @@ frame_move(void *addr) MDBG_OFFSET(ao_lisp_ref(v->atom)), MDBG_OFFSET(ao_lisp_ref(v->val)), f); } - next = ao_lisp_poly_frame(frame->next); - if (!next) + prev = ao_lisp_poly_frame(frame->prev); + if (!prev) break; - ret = ao_lisp_move_memory(&ao_lisp_frame_type, (void **) &next); - if (next != ao_lisp_poly_frame(frame->next)) { - MDBG_MOVE("frame next moved from %d to %d\n", - MDBG_OFFSET(ao_lisp_poly_frame(frame->next)), - MDBG_OFFSET(next)); - frame->next = ao_lisp_frame_poly(next); + ret = ao_lisp_move_memory(&ao_lisp_frame_type, (void **) &prev); + if (prev != ao_lisp_poly_frame(frame->prev)) { + MDBG_MOVE("frame prev moved from %d to %d\n", + MDBG_OFFSET(ao_lisp_poly_frame(frame->prev)), + MDBG_OFFSET(prev)); + frame->prev = ao_lisp_frame_poly(prev); } if (ret) break; - frame = next; + frame = prev; } } @@ -109,15 +109,15 @@ ao_lisp_frame_print(ao_poly p) printf ("{"); if (frame) { - for (f = 0; f < frame->num; f++) { + for (f = 0; f < ao_lisp_frame_num(frame); f++) { if (f != 0) printf(", "); ao_lisp_poly_print(frame->vals[f].atom); printf(" = "); ao_lisp_poly_print(frame->vals[f].val); } - if (frame->next) - ao_lisp_poly_print(frame->next); + if (frame->prev) + ao_lisp_poly_print(frame->prev); } printf("}"); } @@ -126,7 +126,7 @@ ao_poly * ao_lisp_frame_ref(struct ao_lisp_frame *frame, ao_poly atom) { int f; - for (f = 0; f < frame->num; f++) + for (f = 0; f < ao_lisp_frame_num(frame); f++) if (frame->vals[f].atom == atom) return &frame->vals[f].val; return NULL; @@ -143,7 +143,7 @@ ao_lisp_frame_set(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val) return 1; } } - frame = ao_lisp_poly_frame(frame->next); + frame = ao_lisp_poly_frame(frame->prev); } return 0; } @@ -155,25 +155,55 @@ ao_lisp_frame_get(struct ao_lisp_frame *frame, ao_poly atom) ao_poly *ref = ao_lisp_frame_ref(frame, atom); if (ref) return *ref; - frame = ao_lisp_poly_frame(frame->next); + frame = ao_lisp_poly_frame(frame->prev); } return AO_LISP_NIL; } +struct ao_lisp_frame *ao_lisp_frame_free_list[AO_LISP_FRAME_FREE]; + struct ao_lisp_frame * ao_lisp_frame_new(int num) { - struct ao_lisp_frame *frame = ao_lisp_alloc(frame_num_size(num)); + struct ao_lisp_frame *frame; - if (!frame) - return NULL; + if (num < AO_LISP_FRAME_FREE && (frame = ao_lisp_frame_free_list[num])) + ao_lisp_frame_free_list[num] = ao_lisp_poly_frame(frame->prev); + else { + frame = ao_lisp_alloc(frame_num_size(num)); + if (!frame) + return NULL; + } frame->type = AO_LISP_FRAME; - frame->num = num; - frame->next = AO_LISP_NIL; + frame->_num = num; + frame->prev = AO_LISP_NIL; memset(frame->vals, '\0', num * sizeof (struct ao_lisp_val)); return frame; } +ao_poly +ao_lisp_frame_mark(struct ao_lisp_frame *frame) +{ + if (!frame) + return AO_LISP_NIL; + if (frame->_num == 0xff) + ao_lisp_abort(); + frame->_num |= AO_LISP_FRAME_MARK; + return ao_lisp_frame_poly(frame); +} + +void +ao_lisp_frame_free(struct ao_lisp_frame *frame) +{ + if (!ao_lisp_frame_marked(frame)) { + int num = ao_lisp_frame_num(frame); + if (num < AO_LISP_FRAME_FREE) { + frame->prev = ao_lisp_frame_poly(ao_lisp_frame_free_list[num]); + ao_lisp_frame_free_list[num] = frame; + } + } +} + static struct ao_lisp_frame * ao_lisp_frame_realloc(struct ao_lisp_frame **frame_ref, int new_num) { @@ -181,7 +211,7 @@ ao_lisp_frame_realloc(struct ao_lisp_frame **frame_ref, int new_num) struct ao_lisp_frame *new; int copy; - if (new_num == frame->num) + if (new_num == ao_lisp_frame_num(frame)) return frame; new = ao_lisp_frame_new(new_num); if (!new) @@ -192,10 +222,11 @@ ao_lisp_frame_realloc(struct ao_lisp_frame **frame_ref, int new_num) */ frame = *frame_ref; copy = new_num; - if (copy > frame->num) - copy = frame->num; + if (copy > ao_lisp_frame_num(frame)) + copy = ao_lisp_frame_num(frame); memcpy(new->vals, frame->vals, copy * sizeof (struct ao_lisp_val)); - new->next = frame->next; + new->prev = frame->prev; + ao_lisp_frame_free(frame); return new; } @@ -210,7 +241,7 @@ ao_lisp_frame_add(struct ao_lisp_frame **frame_ref, ao_poly atom, ao_poly val) ao_lisp_poly_stash(0, atom); ao_lisp_poly_stash(1, val); if (frame) { - f = frame->num; + f = ao_lisp_frame_num(frame); frame = ao_lisp_frame_realloc(frame_ref, f + 1); } else { f = 0; diff --git a/src/lisp/ao_lisp_lambda.c b/src/lisp/ao_lisp_lambda.c index 0dd8c698..8b761714 100644 --- a/src/lisp/ao_lisp_lambda.c +++ b/src/lisp/ao_lisp_lambda.c @@ -94,7 +94,7 @@ ao_lisp_lambda_alloc(struct ao_lisp_cons *code, int args) lambda->type = AO_LISP_LAMBDA; lambda->args = args; lambda->code = ao_lisp_cons_poly(code); - lambda->frame = ao_lisp_frame_poly(ao_lisp_frame_current); + lambda->frame = ao_lisp_frame_mark(ao_lisp_frame_current); DBGI("build frame: "); DBG_POLY(lambda->frame); DBG("\n"); DBG_STACK(); return ao_lisp_lambda_poly(lambda); @@ -179,7 +179,7 @@ ao_lisp_lambda_eval(void) next_frame->vals[0].val = cons->cdr; break; } - next_frame->next = lambda->frame; + next_frame->prev = lambda->frame; DBGI("eval frame: "); DBG_POLY(ao_lisp_frame_poly(next_frame)); DBG("\n"); ao_lisp_frame_current = next_frame; ao_lisp_stack->frame = ao_lisp_frame_poly(ao_lisp_frame_current); diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index e7ece960..7e7464c4 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -214,8 +214,16 @@ static const struct ao_lisp_root ao_lisp_root[] = { static const void ** const ao_lisp_cache[] = { (const void **) &ao_lisp_cons_free_list, (const void **) &ao_lisp_stack_free_list, + (const void **) &ao_lisp_frame_free_list[0], + (const void **) &ao_lisp_frame_free_list[1], + (const void **) &ao_lisp_frame_free_list[2], + (const void **) &ao_lisp_frame_free_list[3], }; +#if AO_LISP_FRAME_FREE != 4 +#error Unexpected AO_LISP_FRAME_FREE value +#endif + #define AO_LISP_CACHE (sizeof (ao_lisp_cache) / sizeof (ao_lisp_cache[0])) #define AO_LISP_BUSY_SIZE ((AO_LISP_POOL + 31) / 32) -- cgit v1.2.3 From 5c1fa73f159de9d9839e8619494c26931521d2d4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 15 Nov 2016 20:20:14 -0800 Subject: altos/lisp: Do better checking for un-evaluated macros in ROM Need to look at immediate lambdas as well, and also deal with recursive functions by checking for recursion at each atom dereference. Signed-off-by: Keith Packard --- src/lisp/ao_lisp_make_const.c | 120 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 104 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index ae53bd35..416a95d9 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -115,29 +115,109 @@ ao_fec_crc(const uint8_t *bytes, uint8_t len) return crc; } +struct ao_lisp_macro_stack { + struct ao_lisp_macro_stack *next; + ao_poly p; +}; + +struct ao_lisp_macro_stack *macro_stack; + int +ao_lisp_macro_push(ao_poly p) +{ + struct ao_lisp_macro_stack *m = macro_stack; + + while (m) { + if (m->p == p) + return 1; + m = m->next; + } + m = malloc (sizeof (struct ao_lisp_macro_stack)); + m->p = p; + m->next = macro_stack; + macro_stack = m; +} + +void +ao_lisp_macro_pop(void) +{ + struct ao_lisp_macro_stack *m = macro_stack; + + macro_stack = m->next; + free(m); +} + +#define DBG_MACRO 1 +#if DBG_MACRO +int macro_scan_depth; + +void indent(void) +{ + int i; + for (i = 0; i < macro_scan_depth; i++) + printf(" "); +} +#define MACRO_DEBUG(a) a +#else +#define MACRO_DEBUG(a) +#endif + +ao_poly +ao_has_macro(ao_poly p); + +ao_poly +ao_macro_test_get(ao_poly atom) +{ + ao_poly *ref = ao_lisp_atom_ref(ao_lisp_frame_global, atom); + if (ref) + return *ref; + return AO_LISP_NIL; +} + +ao_poly ao_is_macro(ao_poly p) { struct ao_lisp_builtin *builtin; struct ao_lisp_lambda *lambda; + ao_poly ret; -// printf ("macro scanning "); ao_lisp_poly_print(p); printf("\n"); + MACRO_DEBUG(indent(); printf ("is macro "); ao_lisp_poly_print(p); printf("\n"); ++macro_scan_depth); switch (ao_lisp_poly_type(p)) { case AO_LISP_ATOM: - return ao_is_macro(ao_lisp_atom_get(p)); + if (ao_lisp_macro_push(p)) + ret = AO_LISP_NIL; + else { + if (ao_is_macro(ao_macro_test_get(p))) + ret = p; + else + ret = AO_LISP_NIL; + ao_lisp_macro_pop(); + } + break; + case AO_LISP_CONS: + ret = ao_has_macro(p); + break; case AO_LISP_BUILTIN: builtin = ao_lisp_poly_builtin(p); if ((builtin->args & AO_LISP_FUNC_MASK) == AO_LISP_FUNC_MACRO) - return 1; - return 0; + ret = p; + else + ret = 0; + break; + case AO_LISP_LAMBDA: lambda = ao_lisp_poly_lambda(p); if (lambda->args == AO_LISP_FUNC_MACRO) - return 1; - return 0; + ret = p; + else + ret = ao_has_macro(lambda->code); + break; default: - return 0; + ret = AO_LISP_NIL; + break; } + MACRO_DEBUG(--macro_scan_depth; indent(); printf ("... "); ao_lisp_poly_print(ret); printf("\n")); + return ret; } ao_poly @@ -150,27 +230,35 @@ ao_has_macro(ao_poly p) if (p == AO_LISP_NIL) return AO_LISP_NIL; + MACRO_DEBUG(indent(); printf("has macro "); ao_lisp_poly_print(p); printf("\n"); ++macro_scan_depth); switch (ao_lisp_poly_type(p)) { case AO_LISP_LAMBDA: lambda = ao_lisp_poly_lambda(p); - return ao_has_macro(lambda->code); + p = ao_has_macro(lambda->code); + break; case AO_LISP_CONS: cons = ao_lisp_poly_cons(p); - if (ao_is_macro(cons->car)) - return cons->car; + if ((p = ao_is_macro(cons->car))) + break; cons = ao_lisp_poly_cons(cons->cdr); + p = AO_LISP_NIL; while (cons) { m = ao_has_macro(cons->car); - if (m) - return m; + if (m) { + p = m; + break; + } cons = ao_lisp_poly_cons(cons->cdr); } - return AO_LISP_NIL; + break; default: - return AO_LISP_NIL; + p = AO_LISP_NIL; + break; } + MACRO_DEBUG(--macro_scan_depth; indent(); printf("... "); ao_lisp_poly_print(p); printf("\n")); + return p; } int @@ -269,13 +357,13 @@ main(int argc, char **argv) /* Reduce to referenced values */ ao_lisp_collect(); - for (f = 0; f < ao_lisp_frame_global->num; f++) { + for (f = 0; f < ao_lisp_frame_num(ao_lisp_frame_global); f++) { val = ao_has_macro(ao_lisp_frame_global->vals[f].val); if (val != AO_LISP_NIL) { printf("error: function %s contains unresolved macro: ", ao_lisp_poly_atom(ao_lisp_frame_global->vals[f].atom)->name); ao_lisp_poly_print(val); - printf(stderr, "\n"); + printf("\n"); exit(1); } } -- cgit v1.2.3 From 1a00bf4ac12a6505d4b23d94e99b4b46bf679020 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 15 Nov 2016 20:21:47 -0800 Subject: altos/lisp: Allow macro/nlambda/lexpr to have multiple args Entries from the params are bound to the formals with whatever remaining formals there are bound to the last argument as a list. This makes writing functions a bit easier. Signed-off-by: Keith Packard --- src/lisp/ao_lisp_lambda.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp_lambda.c b/src/lisp/ao_lisp_lambda.c index 8b761714..186236f6 100644 --- a/src/lisp/ao_lisp_lambda.c +++ b/src/lisp/ao_lisp_lambda.c @@ -134,6 +134,8 @@ ao_lisp_lambda_eval(void) struct ao_lisp_frame *next_frame; int args_wanted; int args_provided; + int f; + struct ao_lisp_cons *vals DBGI("lambda "); DBG_POLY(ao_lisp_lambda_poly(lambda)); DBG("\n"); @@ -141,12 +143,14 @@ ao_lisp_lambda_eval(void) /* Create a frame to hold the variables */ - if (lambda->args == AO_LISP_FUNC_LAMBDA) - args_provided = ao_lisp_cons_length(cons) - 1; - else - args_provided = 1; - if (args_wanted != args_provided) - return ao_lisp_error(AO_LISP_INVALID, "need %d args, not %d", args_wanted, args_provided); + args_provided = ao_lisp_cons_length(cons) - 1; + if (lambda->args == AO_LISP_FUNC_LAMBDA) { + if (args_wanted != args_provided) + return ao_lisp_error(AO_LISP_INVALID, "need %d args, got %d", args_wanted, args_provided); + } else { + if (args_provided < args_wanted - 1) + return ao_lisp_error(AO_LISP_INVALID, "need at least %d args, got %d", args_wanted, args_provided); + } next_frame = ao_lisp_frame_new(args_wanted); @@ -155,12 +159,10 @@ ao_lisp_lambda_eval(void) cons = ao_lisp_poly_cons(ao_lisp_stack->values); code = ao_lisp_poly_cons(lambda->code); args = ao_lisp_poly_cons(ao_lisp_arg(code, 0)); + vals = ao_lisp_poly_cons(cons->cdr); switch (lambda->args) { - case AO_LISP_FUNC_LAMBDA: { - int f; - struct ao_lisp_cons *vals = ao_lisp_poly_cons(cons->cdr); - + case AO_LISP_FUNC_LAMBDA: for (f = 0; f < args_wanted; f++) { DBGI("bind "); DBG_POLY(args->car); DBG(" = "); DBG_POLY(vals->car); DBG("\n"); next_frame->vals[f].atom = args->car; @@ -170,13 +172,19 @@ ao_lisp_lambda_eval(void) } ao_lisp_cons_free(cons); break; - } case AO_LISP_FUNC_LEXPR: case AO_LISP_FUNC_NLAMBDA: case AO_LISP_FUNC_MACRO: - DBGI("bind "); DBG_POLY(args->car); DBG(" = "); DBG_POLY(cons->cdr); DBG("\n"); - next_frame->vals[0].atom = args->car; - next_frame->vals[0].val = cons->cdr; + for (f = 0; f < args_wanted - 1; f++) { + DBGI("bind "); DBG_POLY(args->car); DBG(" = "); DBG_POLY(vals->car); DBG("\n"); + next_frame->vals[f].atom = args->car; + next_frame->vals[f].val = vals->car; + args = ao_lisp_poly_cons(args->cdr); + vals = ao_lisp_poly_cons(vals->cdr); + } + DBGI("bind "); DBG_POLY(args->car); DBG(" = "); DBG_POLY(); DBG("\n"); + next_frame->vals[f].atom = args->car; + next_frame->vals[f].val = ao_lisp_cons_poly(vals); break; } next_frame->prev = lambda->frame; -- cgit v1.2.3 From ac0f7768659e288338bf452b4248ae3572ea2f7d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 15 Nov 2016 20:22:54 -0800 Subject: altos/lisp: Take advantage of multi-arg macros. Add more ROM funcs Added nth, or and and. Signed-off-by: Keith Packard --- src/lisp/ao_lisp_const.lisp | 164 +++++++++++++++++++++++++++----------------- 1 file changed, 101 insertions(+), 63 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp_const.lisp b/src/lisp/ao_lisp_const.lisp index 9d8af588..4dc63bbf 100644 --- a/src/lisp/ao_lisp_const.lisp +++ b/src/lisp/ao_lisp_const.lisp @@ -1,14 +1,21 @@ - ; basic list accessors - - -(setq cadr (lambda (l) (car (cdr l)))) -(setq caddr (lambda (l) (car (cdr (cdr l))))) -(setq list (lexpr (l) l)) - - ; evaluate a list of sexprs - -;(setq progn (lexpr (l) (last l))) - +; +; Copyright © 2016 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 2 of the License, or +; (at your option) any later version. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; Lisp code placed in ROM + + ; return a list containing all of the arguments + +(set (quote list) (lexpr (l) l)) ; ; Define a variable without returning the value @@ -16,22 +23,82 @@ ; having lots of output generated ; -(setq def (macro (def-param) +(setq def (macro (name val rest) (list 'progn (list 'set - (list - 'quote - (car def-param)) - (cadr def-param) - ) + (list 'quote name) + val) + (list 'quote name) + ) + ) + ) + + ; + ; A slightly more convenient form + ; for defining lambdas. + ; + ; (defun () s-exprs) + ; + +(def defun (macro (name args exprs) (list - 'quote - (car def-param) + def + name + (list + 'lambda + args + (cond ((cdr exprs) + (cons progn exprs)) + ((car exprs)) + ) + ) ) ) + ) + ; basic list accessors + + +(defun cadr (l) (car (cdr l))) + +(defun caddr (l) (car (cdr (cdr l)))) + +(defun nth (list n) + (cond ((= n 0) (car list)) + ((nth (cdr list) (1- n))) + ) + ) + + ; simple math operators + +(defun 1+ (x) (+ x 1)) +(defun 1- (x) (- x 1)) + + ; boolean operators + +(def or (lexpr (l) + (let ((ret nil)) + (while l + (cond ((setq ret (car l)) + (setq l nil)) + ((setq l (cdr l))))) + ret ) + ) + ) + +(def and (lexpr (l) + (let ((ret t)) + (while l + (cond ((setq ret (car l)) + (setq l (cdr l))) + ((setq ret (setq l nil))) + ) + ) + ret + ) + ) ) ; define a set of local @@ -52,8 +119,8 @@ ; ; (let ((x 1) (y)) (setq y (+ x 1)) y) -(def let (macro (let-param) - ((lambda (vars exprs make-names make-exprs make-nils) +(def let (macro (vars exprs) + ((lambda (make-names make-exprs make-nils) (progn ; @@ -67,12 +134,12 @@ ) ) ) - ; + ; the set of expressions is ; the list of set expressions ; pre-pended to the ; expressions to evaluate - ; + (setq make-exprs (lambda (vars exprs) (progn (cond (vars (cons @@ -90,20 +157,22 @@ ) ) ) - (setq exprs (make-exprs vars exprs)) - ; ; the parameters to the lambda is a list ; of nils of the right length - ; + (setq make-nils (lambda (vars) (cond (vars (cons nil (make-nils (cdr vars)))) ) ) ) - ; + ; prepend the set operations + ; to the expressions + + (setq exprs (make-exprs vars exprs)) + ; build the lambda. - ; + (cons (list 'lambda @@ -116,8 +185,6 @@ ) ) ) - (car let-param) - (cdr let-param) () () () @@ -125,38 +192,9 @@ ) ) - ; - ; A slightly more convenient form - ; for defining lambdas. - ; - ; (defun () s-exprs) - ; + ; run the let macro once to + ; evaluate all of the internal + ; macro calls -(def defun (macro (defun-param) - (let ((name (car defun-param)) - (args (cadr defun-param)) - (exprs (cdr (cdr defun-param)))) - (list - def - name - (list - 'lambda - args - (cond ((cdr exprs) - (cons progn exprs)) - ((car exprs)) - ) - ) - ) - ) - ) - ) - - ; simple math operators - ; - ; Do these last to run defun - ; at least once so the let macro - ; is resolved +(let ((let-param 1))) -(defun 1+ (x) (+ x 1)) -(defun 1- (x) (- x 1)) -- cgit v1.2.3 From 5161f6d78647591cc7ab8774a04edbc68a09f689 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 15 Nov 2016 20:24:33 -0800 Subject: altos/lambdakey: Strip out unused code Make space for more lisp bits! Signed-off-by: Keith Packard --- src/lambdakey-v1.0/Makefile | 3 +-- src/lambdakey-v1.0/ao_lambdakey.c | 1 - src/lambdakey-v1.0/ao_pins.h | 6 ------ 3 files changed, 1 insertion(+), 9 deletions(-) (limited to 'src') diff --git a/src/lambdakey-v1.0/Makefile b/src/lambdakey-v1.0/Makefile index feadfa91..a4d78736 100644 --- a/src/lambdakey-v1.0/Makefile +++ b/src/lambdakey-v1.0/Makefile @@ -30,11 +30,10 @@ ALTOS_SRC = \ ao_led.c \ ao_dma_stm.c \ ao_stdio.c \ + ao_mutex.c \ ao_panic.c \ ao_timer.c \ - ao_mutex.c \ ao_usb_stm.c \ - ao_serial_stm.c \ ao_flash_stm.c \ ao_lisp_lex.c \ ao_lisp_mem.c \ diff --git a/src/lambdakey-v1.0/ao_lambdakey.c b/src/lambdakey-v1.0/ao_lambdakey.c index 8353d811..8bd344cf 100644 --- a/src/lambdakey-v1.0/ao_lambdakey.c +++ b/src/lambdakey-v1.0/ao_lambdakey.c @@ -33,7 +33,6 @@ void main(void) ao_timer_init(); ao_dma_init(); ao_usb_init(); - ao_serial_init(); ao_cmd_init(); ao_cmd_register(blink_cmds); ao_start_scheduler(); diff --git a/src/lambdakey-v1.0/ao_pins.h b/src/lambdakey-v1.0/ao_pins.h index 167d0857..2ba79c01 100644 --- a/src/lambdakey-v1.0/ao_pins.h +++ b/src/lambdakey-v1.0/ao_pins.h @@ -54,10 +54,4 @@ #define IS_FLASH_LOADER 0 -#define HAS_SERIAL_2 1 -#define SERIAL_2_PA2_PA15 1 -#define USE_SERIAL_2_FLOW 0 -#define USE_SERIAL_2_STDIN 1 -#define DELAY_SERIAL_2_STDIN 0 - #endif /* _AO_PINS_H_ */ -- cgit v1.2.3 From 472ecec64213e6c37b588d69ca2e8efd5e9abe36 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 15 Nov 2016 20:25:03 -0800 Subject: altos/lisp: remove nth from hanoi.lisp It's now in ROM. Signed-off-by: Keith Packard --- src/test/ao_lisp_os.h | 2 +- src/test/hanoi.lisp | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) (limited to 'src') diff --git a/src/test/ao_lisp_os.h b/src/test/ao_lisp_os.h index 8b9c1475..dedcca28 100644 --- a/src/test/ao_lisp_os.h +++ b/src/test/ao_lisp_os.h @@ -23,7 +23,7 @@ #include #define AO_LISP_POOL_TOTAL 3072 -#define AO_LISP_SAVE +#define AO_LISP_SAVE 1 extern int ao_lisp_getc(void); diff --git a/src/test/hanoi.lisp b/src/test/hanoi.lisp index 66a8d04b..aece2ba0 100644 --- a/src/test/hanoi.lisp +++ b/src/test/hanoi.lisp @@ -106,12 +106,6 @@ ) ) -(defun nth (list n) - (cond ((= n 0) (car list)) - ((nth (cdr list) (1- n))) - ) - ) - ; Replace a stack in the list of stacks ; with a new value -- cgit v1.2.3 From 8406ddf8f0bd5453d6213973daed35991f80972a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 15 Nov 2016 20:37:59 -0800 Subject: altos/lisp: Make hanoi example output a bit prettier Make the towers symmetrical instead of lopsided. Much nicer looking. Signed-off-by: Keith Packard --- src/test/hanoi.lisp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/test/hanoi.lisp b/src/test/hanoi.lisp index aece2ba0..387e696a 100644 --- a/src/test/hanoi.lisp +++ b/src/test/hanoi.lisp @@ -32,9 +32,7 @@ ; Here's the pieces to display -(setq stack '("*" "**" "***" "****" "*****" "******" "*******")) - -(setq top (+ (length stack) 3)) +(setq stack '(" * " " *** " " ***** " " ******* " " ********* " "***********")) ; ; Here's all of the stacks of pieces @@ -55,7 +53,7 @@ ) ) (t (progn - (display-string x y " ") + (display-string x y " ") (display-stack x (1+ y) (1- clear) stack) ) ) @@ -94,6 +92,7 @@ (defun reset-stacks () (setq stacks (list stack nil nil)) + (setq top (+ (length stack) 3)) (length stack) ) -- cgit v1.2.3 From c8f9db184cc929ebde845730a6d4b7864e423a84 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 16 Nov 2016 12:34:14 -0800 Subject: altos/lisp: Add incremental collection Realizing that long-lived objects will eventually float to the bottom of the heap, I added a simple hack to the collector that 'remembers' the top of the heap the last time a full collect was run and then runs incremental collects looking to shift only objects above that boundary. That doesn't perfectly capture the bounds of transient objects, but does manage to reduce the amount of time spent not moving persistent objects each time through the collector. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 10 +++-- src/lisp/ao_lisp_make_const.c | 4 +- src/lisp/ao_lisp_mem.c | 97 +++++++++++-------------------------------- src/lisp/ao_lisp_save.c | 4 +- src/test/ao_lisp_test.c | 7 +++- 5 files changed, 42 insertions(+), 80 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index bcb0a17f..e9432913 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -421,7 +421,8 @@ ao_lisp_builtin_poly(struct ao_lisp_builtin *b) /* memory functions */ -extern int ao_lisp_collects; +extern int ao_lisp_collects[2]; +extern int ao_lisp_freed[2]; /* returns 1 if the object was already marked */ int @@ -445,8 +446,11 @@ ao_lisp_move_memory(const struct ao_lisp_type *type, void **ref); void * ao_lisp_alloc(int size); -void -ao_lisp_collect(void); +#define AO_LISP_COLLECT_FULL 1 +#define AO_LISP_COLLECT_INCREMENTAL 0 + +int +ao_lisp_collect(uint8_t style); void ao_lisp_cons_stash(int id, struct ao_lisp_cons *cons); diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index 416a95d9..60bb80f0 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -147,7 +147,7 @@ ao_lisp_macro_pop(void) free(m); } -#define DBG_MACRO 1 +#define DBG_MACRO 0 #if DBG_MACRO int macro_scan_depth; @@ -355,7 +355,7 @@ main(int argc, char **argv) } /* Reduce to referenced values */ - ao_lisp_collect(); + ao_lisp_collect(AO_LISP_COLLECT_FULL); for (f = 0; f < ao_lisp_frame_num(ao_lisp_frame_global); f++) { val = ao_has_macro(ao_lisp_frame_global->vals[f].val); diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 7e7464c4..37d0af2b 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -36,10 +36,6 @@ uint8_t ao_lisp_pool[AO_LISP_POOL + AO_LISP_POOL_EXTRA] __attribute__((aligned(4 #endif -#if 0 -#define MDBG_POOL -#endif - #if DBG_MEM int dbg_move_depth; int dbg_mem = DBG_MEM_START; @@ -436,15 +432,19 @@ ao_lisp_poly_mark_ref(ao_poly *p, uint8_t do_note_cons) return ao_lisp_poly_mark(*p, do_note_cons); } -int ao_lisp_collects; +int ao_lisp_collects[2]; +int ao_lisp_freed[2]; -void -ao_lisp_collect(void) +int ao_lisp_last_top; + +int +ao_lisp_collect(uint8_t style) { + int ret; int i; int top; -#if DBG_MEM int loops = 0; +#if DBG_MEM int marked; int moved; struct ao_lisp_record *mark_record = NULL, *move_record = NULL; @@ -453,15 +453,18 @@ ao_lisp_collect(void) marked = moved = 0; #endif - ++ao_lisp_collects; + ++ao_lisp_collects[style]; /* Clear references to all caches */ for (i = 0; i < (int) AO_LISP_CACHE; i++) *ao_lisp_cache[i] = NULL; - chunk_low = 0; - top = 0; + if (style == AO_LISP_COLLECT_FULL) { + chunk_low = top = 0; + } else { + chunk_low = top = ao_lisp_last_top; + } for (;;) { - MDBG_DO(loops++); + loops++; MDBG_MOVE("move chunks from %d to %d\n", chunk_low, top); /* Find the sizes of the first chunk of objects to move */ memset(ao_lisp_chunk, '\0', sizeof (ao_lisp_chunk)); @@ -542,12 +545,18 @@ ao_lisp_collect(void) if (chunk_last != AO_LISP_NCHUNK) break; } + ret = ao_lisp_top - top; + ao_lisp_freed[style] += ret; + ao_lisp_top = top; + if (style == AO_LISP_COLLECT_FULL || ao_lisp_last_top == 0) + ao_lisp_last_top = top; MDBG_DO(memset(ao_lisp_chunk, '\0', sizeof (ao_lisp_chunk)); walk(ao_lisp_mark_ref, ao_lisp_poly_mark_ref)); -// printf ("collect. top %d loops %d\n", top, loops); +// printf ("collect. style %d loops %d freed %d\n", style, loops, ret); + return ret; } /* @@ -737,45 +746,6 @@ ao_lisp_poly_move(ao_poly *ref, uint8_t do_note_cons) return ret; } -#ifdef MDBG_POOL -static int AO_LISP_POOL_CUR = AO_LISP_POOL / 8; - -static void -ao_lisp_poison(void) -{ - int i; - - printf("poison\n"); - ao_lisp_mark_busy(); - for (i = 0; i < AO_LISP_POOL_CUR; i += 4) { - uint32_t *a = (uint32_t *) &ao_lisp_pool[i]; - if (!busy_object(ao_lisp_busy, a)) - *a = 0xBEEFBEEF; - } - for (i = 0; i < AO_LISP_POOL_CUR; i += 2) { - ao_poly *a = (uint16_t *) &ao_lisp_pool[i]; - ao_poly p = *a; - - if (!ao_lisp_is_const(p)) { - void *r = ao_lisp_ref(p); - - if (ao_lisp_pool <= (uint8_t *) r && - (uint8_t *) r <= ao_lisp_pool + AO_LISP_POOL_CUR) - { - if (!busy_object(ao_lisp_busy, r)) { - printf("missing reference from %d to %d\n", - (int) ((uint8_t *) a - ao_lisp_pool), - (int) ((uint8_t *) r - ao_lisp_pool)); - } - } - } - } -} - -#else -#define AO_LISP_POOL_CUR AO_LISP_POOL -#endif - #if DBG_MEM void ao_lisp_validate(void) @@ -789,7 +759,6 @@ int dbg_allocs; #endif - void * ao_lisp_alloc(int size) { @@ -798,26 +767,10 @@ ao_lisp_alloc(int size) MDBG_DO(++dbg_allocs); MDBG_DO(if (dbg_validate) ao_lisp_validate()); size = ao_lisp_size_round(size); - if (ao_lisp_top + size > AO_LISP_POOL_CUR) { -#ifdef MDBG_POOL - if (AO_LISP_POOL_CUR < AO_LISP_POOL) { - AO_LISP_POOL_CUR += AO_LISP_POOL / 8; - ao_lisp_poison(); - } else -#endif - ao_lisp_collect(); -#ifdef MDBG_POOL + if (ao_lisp_top + size > AO_LISP_POOL) { + if (!ao_lisp_collect(AO_LISP_COLLECT_INCREMENTAL) && + !ao_lisp_collect(AO_LISP_COLLECT_FULL)) { - int i; - - for (i = ao_lisp_top; i < AO_LISP_POOL; i += 4) { - uint32_t *p = (uint32_t *) &ao_lisp_pool[i]; - *p = 0xbeefbeef; - } - } -#endif - - if (ao_lisp_top + size > AO_LISP_POOL) { ao_lisp_error(AO_LISP_OOM, "out of memory"); return NULL; } diff --git a/src/lisp/ao_lisp_save.c b/src/lisp/ao_lisp_save.c index d5f28e7d..e6e8b65e 100644 --- a/src/lisp/ao_lisp_save.c +++ b/src/lisp/ao_lisp_save.c @@ -23,7 +23,7 @@ ao_lisp_save(struct ao_lisp_cons *cons) #ifdef AO_LISP_SAVE struct ao_lisp_os_save *os = (struct ao_lisp_os_save *) &ao_lisp_pool[AO_LISP_POOL]; - ao_lisp_collect(); + ao_lisp_collect(AO_LISP_COLLECT_FULL); os->atoms = ao_lisp_atom_poly(ao_lisp_atoms); os->globals = ao_lisp_frame_poly(ao_lisp_frame_global); os->const_checksum = ao_lisp_const_checksum; @@ -64,7 +64,7 @@ ao_lisp_restore(struct ao_lisp_cons *cons) /* Reset the allocator */ ao_lisp_top = AO_LISP_POOL; - ao_lisp_collect(); + ao_lisp_collect(AO_LISP_COLLECT_FULL); /* Re-create the evaluator stack */ if (!ao_lisp_eval_restart()) diff --git a/src/test/ao_lisp_test.c b/src/test/ao_lisp_test.c index bbaa3f9d..720355d2 100644 --- a/src/test/ao_lisp_test.c +++ b/src/test/ao_lisp_test.c @@ -101,5 +101,10 @@ main (int argc, char **argv) ao_lisp_file = NULL; } ao_lisp_read_eval_print(); - printf ("%d collects\n", ao_lisp_collects); + printf ("collects: full: %d incremental %d\n", + ao_lisp_collects[AO_LISP_COLLECT_FULL], + ao_lisp_collects[AO_LISP_COLLECT_INCREMENTAL]); + printf ("freed: full %d incremental %d\n", + ao_lisp_freed[AO_LISP_COLLECT_FULL], + ao_lisp_freed[AO_LISP_COLLECT_INCREMENTAL]); } -- cgit v1.2.3 From daa06c8dedc6dc1cf21936ee2769d9d25f0567bd Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 16 Nov 2016 13:19:20 -0800 Subject: altos/lisp: Optimize chunk searching in collect Note range of existing chunks to exclude objects outside. Only look at chunks which have been set to reduce loop cost. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 1 + src/lisp/ao_lisp_const.lisp | 62 ++++++++++++++++++++++--------------------- src/lisp/ao_lisp_make_const.c | 3 ++- src/lisp/ao_lisp_mem.c | 54 ++++++++++++++++++++++++++----------- src/test/ao_lisp_test.c | 24 +++++++++++++++++ src/test/hanoi.lisp | 11 +++++++- 6 files changed, 107 insertions(+), 48 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index e9432913..ea8d98b5 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -423,6 +423,7 @@ ao_lisp_builtin_poly(struct ao_lisp_builtin *b) extern int ao_lisp_collects[2]; extern int ao_lisp_freed[2]; +extern int ao_lisp_loops[2]; /* returns 1 if the object was already marked */ int diff --git a/src/lisp/ao_lisp_const.lisp b/src/lisp/ao_lisp_const.lisp index 4dc63bbf..6fbc35b6 100644 --- a/src/lisp/ao_lisp_const.lisp +++ b/src/lisp/ao_lisp_const.lisp @@ -75,32 +75,6 @@ (defun 1+ (x) (+ x 1)) (defun 1- (x) (- x 1)) - ; boolean operators - -(def or (lexpr (l) - (let ((ret nil)) - (while l - (cond ((setq ret (car l)) - (setq l nil)) - ((setq l (cdr l))))) - ret - ) - ) - ) - -(def and (lexpr (l) - (let ((ret t)) - (while l - (cond ((setq ret (car l)) - (setq l (cdr l))) - ((setq ret (setq l nil))) - ) - ) - ret - ) - ) - ) - ; define a set of local ; variables and then evaluate ; a list of sexprs @@ -192,9 +166,37 @@ ) ) - ; run the let macro once to - ; evaluate all of the internal - ; macro calls + ; boolean operators + +(def or (lexpr (l) + (let ((ret nil)) + (while l + (cond ((setq ret (car l)) + (setq l nil)) + ((setq l (cdr l))))) + ret + ) + ) + ) + + ; execute to resolve macros + +(or nil t) + +(def and (lexpr (l) + (let ((ret t)) + (while l + (cond ((setq ret (car l)) + (setq l (cdr l))) + ((setq ret (setq l nil))) + ) + ) + ret + ) + ) + ) + + ; execute to resolve macros -(let ((let-param 1))) +(and t nil) diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index 60bb80f0..0f243eb0 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -136,6 +136,7 @@ ao_lisp_macro_push(ao_poly p) m->p = p; m->next = macro_stack; macro_stack = m; + return 0; } void @@ -397,7 +398,7 @@ main(int argc, char **argv) fprintf(out, " 0x%04x\n", ao_lisp_atom_poly(a)); } fprintf(out, "#ifdef AO_LISP_CONST_BITS\n"); - fprintf(out, "const uint8_t ao_lisp_const[] = {"); + fprintf(out, "const uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute((aligned(4))) = {"); for (o = 0; o < ao_lisp_top; o++) { uint8_t c; if ((o & 0xf) == 0) diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 37d0af2b..b681dbd5 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -307,18 +307,19 @@ note_cons(void *addr) } } -static uint16_t chunk_low; +static uint16_t chunk_low, chunk_high; static uint16_t chunk_first, chunk_last; +static int chunk_busy; static void note_chunk(uint16_t addr, uint16_t size) { int i; - if (addr < chunk_low) + if (addr < chunk_low || chunk_high < addr) return; - for (i = 0; i < AO_LISP_NCHUNK; i++) { + for (i = 0; i < chunk_busy; i++) { if (ao_lisp_chunk[i].size && ao_lisp_chunk[i].old_addr == addr) { #if DBG_MEM if (ao_lisp_chunk[i].size != size) @@ -327,17 +328,30 @@ note_chunk(uint16_t addr, uint16_t size) return; } if (ao_lisp_chunk[i].old_addr > addr) { + int end = min(AO_LISP_NCHUNK, chunk_busy + 1); memmove(&ao_lisp_chunk[i+1], &ao_lisp_chunk[i], - (AO_LISP_NCHUNK - (i+1)) * sizeof (struct ao_lisp_chunk)); - ao_lisp_chunk[i].size = 0; - } - if (ao_lisp_chunk[i].size == 0) { - ao_lisp_chunk[i].old_addr = addr; - ao_lisp_chunk[i].size = size; - return; + (end - (i+1)) * sizeof (struct ao_lisp_chunk)); + break; } } + if (i < AO_LISP_NCHUNK) { + ao_lisp_chunk[i].old_addr = addr; + ao_lisp_chunk[i].size = size; + if (chunk_busy < AO_LISP_NCHUNK) + chunk_busy++; + else + chunk_high = ao_lisp_chunk[AO_LISP_NCHUNK-1].old_addr + + ao_lisp_chunk[AO_LISP_NCHUNK-1].size; + } +} + +static void +reset_chunks(void) +{ + memset(ao_lisp_chunk, '\0', sizeof (ao_lisp_chunk)); + chunk_high = ao_lisp_top; + chunk_busy = 0; } /* @@ -434,6 +448,7 @@ ao_lisp_poly_mark_ref(ao_poly *p, uint8_t do_note_cons) int ao_lisp_collects[2]; int ao_lisp_freed[2]; +int ao_lisp_loops[2]; int ao_lisp_last_top; @@ -453,7 +468,9 @@ ao_lisp_collect(uint8_t style) marked = moved = 0; #endif - ++ao_lisp_collects[style]; + /* The first time through, we're doing a full collect */ + if (ao_lisp_last_top == 0) + style = AO_LISP_COLLECT_FULL; /* Clear references to all caches */ for (i = 0; i < (int) AO_LISP_CACHE; i++) @@ -467,7 +484,7 @@ ao_lisp_collect(uint8_t style) loops++; MDBG_MOVE("move chunks from %d to %d\n", chunk_low, top); /* Find the sizes of the first chunk of objects to move */ - memset(ao_lisp_chunk, '\0', sizeof (ao_lisp_chunk)); + reset_chunks(); walk(ao_lisp_mark_ref, ao_lisp_poly_mark_ref); #if DBG_MEM marked = total_marked; @@ -501,7 +518,6 @@ ao_lisp_collect(uint8_t style) MDBG_MOVE("chunk %d %d not moving\n", ao_lisp_chunk[i].old_addr, ao_lisp_chunk[i].size); - chunk_low = ao_lisp_chunk[i].old_addr + size; } chunk_first = i; @@ -521,7 +537,6 @@ ao_lisp_collect(uint8_t style) &ao_lisp_pool[ao_lisp_chunk[i].old_addr], size); top += size; - chunk_low = ao_lisp_chunk[i].old_addr + size; } chunk_last = i; @@ -544,18 +559,25 @@ ao_lisp_collect(uint8_t style) if (chunk_last != AO_LISP_NCHUNK) break; + + chunk_low = chunk_high; } + + /* Compute amount of memory freed */ ret = ao_lisp_top - top; + + /* Collect stats */ + ++ao_lisp_collects[style]; ao_lisp_freed[style] += ret; + ao_lisp_loops[style] += loops; ao_lisp_top = top; - if (style == AO_LISP_COLLECT_FULL || ao_lisp_last_top == 0) + if (style == AO_LISP_COLLECT_FULL) ao_lisp_last_top = top; MDBG_DO(memset(ao_lisp_chunk, '\0', sizeof (ao_lisp_chunk)); walk(ao_lisp_mark_ref, ao_lisp_poly_mark_ref)); -// printf ("collect. style %d loops %d freed %d\n", style, loops, ret); return ret; } diff --git a/src/test/ao_lisp_test.c b/src/test/ao_lisp_test.c index 720355d2..68e3a202 100644 --- a/src/test/ao_lisp_test.c +++ b/src/test/ao_lisp_test.c @@ -101,10 +101,34 @@ main (int argc, char **argv) ao_lisp_file = NULL; } ao_lisp_read_eval_print(); + printf ("collects: full: %d incremental %d\n", ao_lisp_collects[AO_LISP_COLLECT_FULL], ao_lisp_collects[AO_LISP_COLLECT_INCREMENTAL]); + printf ("freed: full %d incremental %d\n", ao_lisp_freed[AO_LISP_COLLECT_FULL], ao_lisp_freed[AO_LISP_COLLECT_INCREMENTAL]); + + printf("loops: full %d incremental %d\n", + ao_lisp_loops[AO_LISP_COLLECT_FULL], + ao_lisp_loops[AO_LISP_COLLECT_INCREMENTAL]); + + printf("loops per collect: full %f incremental %f\n", + (double) ao_lisp_loops[AO_LISP_COLLECT_FULL] / + (double) ao_lisp_collects[AO_LISP_COLLECT_FULL], + (double) ao_lisp_loops[AO_LISP_COLLECT_INCREMENTAL] / + (double) ao_lisp_collects[AO_LISP_COLLECT_INCREMENTAL]); + + printf("freed per collect: full %f incremental %f\n", + (double) ao_lisp_freed[AO_LISP_COLLECT_FULL] / + (double) ao_lisp_collects[AO_LISP_COLLECT_FULL], + (double) ao_lisp_freed[AO_LISP_COLLECT_INCREMENTAL] / + (double) ao_lisp_collects[AO_LISP_COLLECT_INCREMENTAL]); + + printf("freed per loop: full %f incremental %f\n", + (double) ao_lisp_freed[AO_LISP_COLLECT_FULL] / + (double) ao_lisp_loops[AO_LISP_COLLECT_FULL], + (double) ao_lisp_freed[AO_LISP_COLLECT_INCREMENTAL] / + (double) ao_lisp_loops[AO_LISP_COLLECT_INCREMENTAL]); } diff --git a/src/test/hanoi.lisp b/src/test/hanoi.lisp index 387e696a..7a25656c 100644 --- a/src/test/hanoi.lisp +++ b/src/test/hanoi.lisp @@ -126,7 +126,7 @@ (setq stacks (replace stacks from from-stack)) (setq stacks (replace stacks to to-stack)) (display) - (delay 100) +; (delay 100) ) ) @@ -158,3 +158,12 @@ (clear) (_hanoi len 0 1 2) ) + +(defun hanois(n) + (while (> n 0) + (progn + (hanoi) + (setq l (1- l)) + ) + ) + ) -- cgit v1.2.3 From a7fcf80e22e70516d0b2da314fb17ced20a3f775 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 16 Nov 2016 13:47:49 -0800 Subject: altos/lisp: Allow empty defun bodies This allows for (defun foo()) Signed-off-by: Keith Packard --- src/lisp/ao_lisp_const.lisp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp_const.lisp b/src/lisp/ao_lisp_const.lisp index 6fbc35b6..13bb8139 100644 --- a/src/lisp/ao_lisp_const.lisp +++ b/src/lisp/ao_lisp_const.lisp @@ -49,9 +49,12 @@ (list 'lambda args - (cond ((cdr exprs) - (cons progn exprs)) - ((car exprs)) + (cond (exprs + (cond ((cdr exprs) + (cons progn exprs)) + ((car exprs)) + ) + ) ) ) ) -- cgit v1.2.3 From 9f19cb10cd12f86b12d0599bab5c2ee351d814ae Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 16 Nov 2016 13:59:54 -0800 Subject: altos/test: Disable position independent executables This makes debugging programs so much harder --- src/test/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/test/Makefile b/src/test/Makefile index df24c2b6..fae46ac8 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -10,7 +10,7 @@ INCS=ao_kalman.h ao_ms5607.h ao_log.h ao_data.h altitude-pa.h altitude.h ao_quat KALMAN=make-kalman -CFLAGS=-I.. -I. -I../kernel -I../drivers -I../micropeak -I../product -I../lisp -O0 -g -Wall -DAO_LISP_TEST +CFLAGS=-I.. -I. -I../kernel -I../drivers -I../micropeak -I../product -I../lisp -O3 -g -Wall -DAO_LISP_TEST -no-pie all: $(PROGS) ao_aprs_data.wav -- cgit v1.2.3 From a5ef084659205700aab33e81d20fb89833c03249 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 16 Nov 2016 14:00:38 -0800 Subject: altos/lisp: binary search for chunk in collect Speeds up collect a bit Signed-off-by: Keith Packard --- src/lisp/ao_lisp_mem.c | 69 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index b681dbd5..53ebf757 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -314,36 +314,55 @@ static int chunk_busy; static void note_chunk(uint16_t addr, uint16_t size) { - int i; + int l, r; - if (addr < chunk_low || chunk_high < addr) + if (addr < chunk_low || chunk_high <= addr) return; - for (i = 0; i < chunk_busy; i++) { - if (ao_lisp_chunk[i].size && ao_lisp_chunk[i].old_addr == addr) { -#if DBG_MEM - if (ao_lisp_chunk[i].size != size) - ao_lisp_abort(); -#endif - return; - } - if (ao_lisp_chunk[i].old_addr > addr) { - int end = min(AO_LISP_NCHUNK, chunk_busy + 1); - memmove(&ao_lisp_chunk[i+1], - &ao_lisp_chunk[i], - (end - (i+1)) * sizeof (struct ao_lisp_chunk)); - break; - } - } - if (i < AO_LISP_NCHUNK) { - ao_lisp_chunk[i].old_addr = addr; - ao_lisp_chunk[i].size = size; - if (chunk_busy < AO_LISP_NCHUNK) - chunk_busy++; + /* Binary search for the location */ + l = 0; + r = chunk_busy - 1; + while (l <= r) { + int m = (l + r) >> 1; + if (ao_lisp_chunk[m].old_addr < addr) + l = m + 1; else - chunk_high = ao_lisp_chunk[AO_LISP_NCHUNK-1].old_addr + - ao_lisp_chunk[AO_LISP_NCHUNK-1].size; + r = m - 1; } + /* + * The correct location is always in 'l', with r = l-1 being + * the entry before the right one + */ + +#if DBG_MEM + /* Off the right side */ + if (l >= AO_LISP_NCHUNK) + ao_lisp_abort(); + + /* Off the left side */ + if (l == 0 && chunk_busy && addr > ao_lisp_chunk[0].old_addr) + ao_lisp_abort(); +#endif + + /* Shuffle existing entries right */ + int end = min(AO_LISP_NCHUNK, chunk_busy + 1); + + memmove(&ao_lisp_chunk[l+1], + &ao_lisp_chunk[l], + (end - (l+1)) * sizeof (struct ao_lisp_chunk)); + + /* Add new entry */ + ao_lisp_chunk[l].old_addr = addr; + ao_lisp_chunk[l].size = size; + + /* Increment the number of elements up to the size of the array */ + if (chunk_busy < AO_LISP_NCHUNK) + chunk_busy++; + + /* Set the top address if the array is full */ + if (chunk_busy == AO_LISP_NCHUNK) + chunk_high = ao_lisp_chunk[AO_LISP_NCHUNK-1].old_addr + + ao_lisp_chunk[AO_LISP_NCHUNK-1].size; } static void -- cgit v1.2.3 From bcf5eb5825b1217d74f117b02d09b4ce4b007beb Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 16 Nov 2016 14:12:59 -0800 Subject: altos/lisp: Eliminate compiler warning about array bounds at -O3 Using ao_lisp_pool - 4 caused the compiler to whinge about computing an address outside the bounds of the array. Sigh. Restructure the code to do the adjustment-by-4 in the integer computations instead of the pointer ones. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 3 --- src/lisp/ao_lisp_mem.c | 17 ----------------- src/lisp/ao_lisp_poly.c | 8 ++++---- src/test/Makefile | 2 +- 4 files changed, 5 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index ea8d98b5..25d13fa3 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -118,9 +118,6 @@ ao_lisp_is_const(ao_poly poly) { return poly & AO_LISP_CONST; } -#define AO_LISP_POOL_BASE (ao_lisp_pool - 4) -#define AO_LISP_CONST_BASE (ao_lisp_const - 4) - #define AO_LISP_IS_CONST(a) (ao_lisp_const <= ((uint8_t *) (a)) && ((uint8_t *) (a)) < ao_lisp_const + AO_LISP_POOL_CONST) #define AO_LISP_IS_POOL(a) (ao_lisp_pool <= ((uint8_t *) (a)) && ((uint8_t *) (a)) < ao_lisp_pool + AO_LISP_POOL) diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 53ebf757..12a5ba55 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -252,23 +252,6 @@ static inline uint16_t pool_offset(void *addr) { return ((uint8_t *) addr) - ao_lisp_pool; } -/* - * Convert back and forth between 'poly's used - * as short addresses in the pool and addresses. - * These are used in the chunk code. - */ -static inline ao_poly pool_poly(void *addr) { -#if DBG_MEM - if (!AO_LISP_IS_POOL(addr)) - ao_lisp_abort(); -#endif - return ((uint8_t *) addr) - AO_LISP_POOL_BASE; -} - -static inline void *pool_ref(ao_poly p) { - return AO_LISP_POOL_BASE + p; -} - static inline void mark(uint8_t *tag, int offset) { int byte = offset >> 5; int bit = (offset >> 2) & 7; diff --git a/src/lisp/ao_lisp_poly.c b/src/lisp/ao_lisp_poly.c index 9717fd73..236176e7 100644 --- a/src/lisp/ao_lisp_poly.c +++ b/src/lisp/ao_lisp_poly.c @@ -89,8 +89,8 @@ ao_lisp_ref(ao_poly poly) { if (poly == AO_LISP_NIL) return NULL; if (poly & AO_LISP_CONST) - return (void *) (AO_LISP_CONST_BASE + (poly & AO_LISP_REF_MASK)); - return (void *) (AO_LISP_POOL_BASE + (poly & AO_LISP_REF_MASK)); + return (void *) (ao_lisp_const + (poly & AO_LISP_REF_MASK) - 4); + return (void *) (ao_lisp_pool + (poly & AO_LISP_REF_MASK) - 4); } ao_poly @@ -99,6 +99,6 @@ ao_lisp_poly(const void *addr, ao_poly type) { if (a == NULL) return AO_LISP_NIL; if (AO_LISP_IS_CONST(a)) - return AO_LISP_CONST | (a - AO_LISP_CONST_BASE) | type; - return (a - AO_LISP_POOL_BASE) | type; + return AO_LISP_CONST | (a - ao_lisp_const + 4) | type; + return (a - ao_lisp_pool + 4) | type; } diff --git a/src/test/Makefile b/src/test/Makefile index fae46ac8..0eaa9421 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -10,7 +10,7 @@ INCS=ao_kalman.h ao_ms5607.h ao_log.h ao_data.h altitude-pa.h altitude.h ao_quat KALMAN=make-kalman -CFLAGS=-I.. -I. -I../kernel -I../drivers -I../micropeak -I../product -I../lisp -O3 -g -Wall -DAO_LISP_TEST -no-pie +CFLAGS=-I.. -I. -I../kernel -I../drivers -I../micropeak -I../product -I../lisp -O0 -g -Wall -DAO_LISP_TEST -no-pie all: $(PROGS) ao_aprs_data.wav -- cgit v1.2.3 From d37945f1404043e6bd287ce7ad7a57bc3289609b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 16 Nov 2016 14:59:08 -0800 Subject: altos/lisp: Clean up hanoi.lisp comments. Signed-off-by: Keith Packard --- src/test/hanoi.lisp | 69 +++++++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/test/hanoi.lisp b/src/test/hanoi.lisp index 7a25656c..d8ff2c86 100644 --- a/src/test/hanoi.lisp +++ b/src/test/hanoi.lisp @@ -14,8 +14,7 @@ ; General Public License for more details. ; - -; ANSI control sequences + ; ANSI control sequences (defun move-to (col row) (patom "\033[" row ";" col "H" nil) @@ -30,18 +29,17 @@ (patom str) ) -; Here's the pieces to display + ; Here's the pieces to display (setq stack '(" * " " *** " " ***** " " ******* " " ********* " "***********")) -; -; Here's all of the stacks of pieces -; This is generated when the program is run -; + ; Here's all of the stacks of pieces + ; This is generated when the program is run + (setq stacks nil) -; Display one stack, clearing any -; space above it + ; Display one stack, clearing any + ; space above it (defun display-stack (x y clear stack) (cond ((= 0 clear) @@ -60,14 +58,14 @@ ) ) -; Position of the top of the stack on the screen -; Shorter stacks start further down the screen + ; Position of the top of the stack on the screen + ; Shorter stacks start further down the screen (defun stack-pos (y stack) (- y (length stack)) ) -; Display all of the stacks, spaced 20 columns apart + ; Display all of the stacks, spaced 20 columns apart (defun display-stacks (x y stacks) (cond (stacks (progn @@ -77,8 +75,8 @@ ) ) -; Display all of the stacks, then move the cursor -; out of the way and flush the output + ; Display all of the stacks, then move the cursor + ; out of the way and flush the output (defun display () (display-stacks 0 top stacks) @@ -86,9 +84,9 @@ (flush) ) -; Reset stacks to the starting state, with -; all of the pieces in the first stack and the -; other two empty + ; Reset stacks to the starting state, with + ; all of the pieces in the first stack and the + ; other two empty (defun reset-stacks () (setq stacks (list stack nil nil)) @@ -96,8 +94,8 @@ (length stack) ) -; more functions which could usefully -; be in the rom image + ; more functions which could usefully + ; be in the rom image (defun min (a b) (cond ((< a b) a) @@ -105,8 +103,8 @@ ) ) -; Replace a stack in the list of stacks -; with a new value + ; Replace a stack in the list of stacks + ; with a new value (defun replace (list pos member) (cond ((= pos 0) (cons member (cdr list))) @@ -114,8 +112,8 @@ ) ) -; Move a piece from the top of one stack -; to the top of another + ; Move a piece from the top of one stack + ; to the top of another (defun move-piece (from to) (let ((from-stack (nth stacks from)) @@ -126,7 +124,7 @@ (setq stacks (replace stacks from from-stack)) (setq stacks (replace stacks to to-stack)) (display) -; (delay 100) + (delay 100) ) ) @@ -148,10 +146,10 @@ ) ) -; A pretty interface which -; resets the state of the game, -; clears the screen and runs -; the program + ; A pretty interface which + ; resets the state of the game, + ; clears the screen and runs + ; the program (defun hanoi () (setq len (reset-stacks)) @@ -159,11 +157,14 @@ (_hanoi len 0 1 2) ) + ; Run many in a row to time them + (defun hanois(n) - (while (> n 0) - (progn - (hanoi) - (setq l (1- l)) - ) - ) + (cond ((> n 0) + (progn + (hanoi) + (hanois (1- n)) + ) + ) + ) ) -- cgit v1.2.3 From 2ce7ab37df07b3c1ea1ca9befc06477e3b6cdeac Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 17 Nov 2016 16:04:38 -0800 Subject: altos/lisp: Remove some stale frame debugging checks No-one sets frame->_num to 0xff to hit these Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 7 ------- src/lisp/ao_lisp_frame.c | 2 -- 2 files changed, 9 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 25d13fa3..bcefbabf 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -164,22 +164,15 @@ struct ao_lisp_frame { #define AO_LISP_FRAME_MARK 0x80 static inline int ao_lisp_frame_num(struct ao_lisp_frame *f) { - if (f->_num == 0xff) - ao_lisp_abort(); return f->_num & AO_LISP_FRAME_NUM_MASK; } static inline int ao_lisp_frame_marked(struct ao_lisp_frame *f) { - if (f->_num == 0xff) - ao_lisp_abort(); return f->_num & AO_LISP_FRAME_MARK; } static inline struct ao_lisp_frame * ao_lisp_poly_frame(ao_poly poly) { - struct ao_lisp_frame *frame = ao_lisp_ref(poly); - if (frame && frame->_num == 0xff) - ao_lisp_abort(); return ao_lisp_ref(poly); } diff --git a/src/lisp/ao_lisp_frame.c b/src/lisp/ao_lisp_frame.c index 052d27d7..9d17f6fa 100644 --- a/src/lisp/ao_lisp_frame.c +++ b/src/lisp/ao_lisp_frame.c @@ -186,8 +186,6 @@ ao_lisp_frame_mark(struct ao_lisp_frame *frame) { if (!frame) return AO_LISP_NIL; - if (frame->_num == 0xff) - ao_lisp_abort(); frame->_num |= AO_LISP_FRAME_MARK; return ao_lisp_frame_poly(frame); } -- cgit v1.2.3 From 05ac336ea954c0f5eefabdefb0c8c5747be3fd32 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 17 Nov 2016 16:05:29 -0800 Subject: altos/lisp: Fix error atom name in ao_lisp_length Cut&paste error. Signed-off-by: Keith Packard --- src/lisp/ao_lisp_builtin.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index b808cbc5..6cbcb92c 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -213,9 +213,9 @@ ao_lisp_last(struct ao_lisp_cons *cons) ao_poly ao_lisp_length(struct ao_lisp_cons *cons) { - if (!ao_lisp_check_argc(_ao_lisp_atom_last, cons, 1, 1)) + if (!ao_lisp_check_argc(_ao_lisp_atom_length, cons, 1, 1)) return AO_LISP_NIL; - if (!ao_lisp_check_argt(_ao_lisp_atom_last, cons, 0, AO_LISP_CONS, 1)) + if (!ao_lisp_check_argt(_ao_lisp_atom_length, cons, 0, AO_LISP_CONS, 1)) return AO_LISP_NIL; return ao_lisp_int_poly(ao_lisp_cons_length(ao_lisp_poly_cons(ao_lisp_arg(cons, 0)))); } -- cgit v1.2.3 From 84732aebd10c293101727ba567bfc733dc30efca Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 17 Nov 2016 16:06:05 -0800 Subject: altos/lisp: Dump globals on error Useful for debugging Signed-off-by: Keith Packard --- src/lisp/ao_lisp_error.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/lisp/ao_lisp_error.c b/src/lisp/ao_lisp_error.c index 2b15c418..7ad7b2b5 100644 --- a/src/lisp/ao_lisp_error.c +++ b/src/lisp/ao_lisp_error.c @@ -106,5 +106,8 @@ ao_lisp_error(int error, char *format, ...) va_end(args); printf("\n"); ao_lisp_stack_print(); + printf("Globals:\n\t"); + ao_lisp_frame_print(ao_lisp_frame_poly(ao_lisp_frame_global)); + printf("\n"); return AO_LISP_NIL; } -- cgit v1.2.3 From 51bdee662fdfad1937c576daadd2e5eacac17905 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 17 Nov 2016 16:06:55 -0800 Subject: altos/lisp: Fix uninitialized values in ao_lisp_make_const Signed-off-by: Keith Packard --- src/lisp/ao_lisp_make_const.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index 0f243eb0..495e48cd 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -306,8 +306,8 @@ main(int argc, char **argv) ao_poly val; struct ao_lisp_atom *a; struct ao_lisp_builtin *b; - int in_atom; - char *out_name; + int in_atom = 0; + char *out_name = NULL; int c; in = stdin; -- cgit v1.2.3 From ffaf73407bcdf6bc4120c90212de4a2f52cf7991 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 17 Nov 2016 16:07:42 -0800 Subject: altos/lisp: Compile ao_lisp_make_const -no-pie Makes debugging easier Signed-off-by: Keith Packard --- src/lisp/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lisp/Makefile b/src/lisp/Makefile index b06e10dd..15297999 100644 --- a/src/lisp/Makefile +++ b/src/lisp/Makefile @@ -25,7 +25,7 @@ SRCS=\ OBJS=$(SRCS:.c=.o) -CFLAGS=-DAO_LISP_MAKE_CONST -O0 -g -I. -Wall -Wextra +CFLAGS=-DAO_LISP_MAKE_CONST -O0 -g -I. -Wall -Wextra -no-pie HDRS=\ ao_lisp.h \ -- cgit v1.2.3 From eaa528e4e62ba1d9765888760d387303487b2e01 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 17 Nov 2016 16:08:15 -0800 Subject: altos/lisp: Make lambda, cond and while all have implicit progns This lets all of these execute more than one sexpr, returning the value of the last. Signed-off-by: Keith Packard --- src/lisp/ao_lisp_eval.c | 26 +++++++++++++++----------- src/lisp/ao_lisp_lambda.c | 22 ++++++++++++++-------- 2 files changed, 29 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index 6f56a120..5fa9e0ad 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -310,7 +310,6 @@ ao_lisp_eval_formal(void) * value and re-evaluate it */ prev = ao_lisp_poly_stack(ao_lisp_stack->prev); - ao_lisp_stack->state = eval_sexpr; ao_lisp_stack->sexprs = prev->sexprs; DBGI(".. start macro\n"); @@ -401,10 +400,11 @@ ao_lisp_eval_exec(void) DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); break; case AO_LISP_LAMBDA: - ao_lisp_stack->state = eval_sexpr; DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); - ao_lisp_v = ao_lisp_lambda_eval(); - DBGI(".. sexpr "); DBG_POLY(ao_lisp_v); DBG("\n"); + ao_lisp_stack->state = eval_progn; + v = ao_lisp_lambda_eval(); + ao_lisp_stack->sexprs = v; + DBGI(".. sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); break; } @@ -442,7 +442,6 @@ ao_lisp_eval_cond(void) ao_lisp_stack->state = eval_cond_test; if (!ao_lisp_stack_push()) return 0; - ao_lisp_stack->state = eval_sexpr; } return 1; } @@ -464,11 +463,11 @@ ao_lisp_eval_cond_test(void) DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n"); if (ao_lisp_v) { struct ao_lisp_cons *car = ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car); - struct ao_lisp_cons *c = ao_lisp_poly_cons(car->cdr); + ao_poly c = car->cdr; if (c) { - ao_lisp_stack->state = eval_sexpr; - ao_lisp_v = c->car; + ao_lisp_stack->state = eval_progn; + ao_lisp_stack->sexprs = c; } else ao_lisp_stack->state = eval_val; } else { @@ -502,6 +501,10 @@ ao_lisp_eval_progn(void) } else { ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->car; ao_lisp_stack->sexprs = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr; + + /* If there are more sexprs to do, then come back here, otherwise + * return the value of the last one by just landing in eval_sexpr + */ if (ao_lisp_stack->sexprs) { ao_lisp_stack->state = eval_progn; if (!ao_lisp_stack_push()) @@ -530,7 +533,6 @@ ao_lisp_eval_while(void) ao_lisp_stack->state = eval_while_test; if (!ao_lisp_stack_push()) return 0; - ao_lisp_stack->state = eval_sexpr; } return 1; } @@ -547,11 +549,11 @@ ao_lisp_eval_while_test(void) if (ao_lisp_v) { ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr; - if (ao_lisp_v) - ao_lisp_v = ao_lisp_poly_cons(ao_lisp_v)->car; ao_lisp_stack->state = eval_while; if (!ao_lisp_stack_push()) return 0; + ao_lisp_stack->state = eval_progn; + ao_lisp_stack->sexprs = ao_lisp_v; } else ao_lisp_stack->state = eval_val; @@ -567,6 +569,8 @@ ao_lisp_eval_macro(void) { DBGI("macro: "); DBG_POLY(ao_lisp_v); DBG(" sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); + if (ao_lisp_v == AO_LISP_NIL) + ao_lisp_abort(); if (ao_lisp_poly_type(ao_lisp_v) == AO_LISP_CONS) { *ao_lisp_poly_cons(ao_lisp_stack->sexprs) = *ao_lisp_poly_cons(ao_lisp_v); ao_lisp_v = ao_lisp_stack->sexprs; diff --git a/src/lisp/ao_lisp_lambda.c b/src/lisp/ao_lisp_lambda.c index 186236f6..e2053a6f 100644 --- a/src/lisp/ao_lisp_lambda.c +++ b/src/lisp/ao_lisp_lambda.c @@ -78,8 +78,9 @@ ao_lisp_lambda_alloc(struct ao_lisp_cons *code, int args) if (!lambda) return AO_LISP_NIL; - if (!ao_lisp_check_argc(_ao_lisp_atom_lambda, code, 2, 2)) - return AO_LISP_NIL; + if (!code->cdr) + return ao_lisp_error(AO_LISP_INVALID, "missing parameters to lambda"); + if (!ao_lisp_check_argt(_ao_lisp_atom_lambda, code, 0, AO_LISP_CONS, 1)) return AO_LISP_NIL; f = 0; @@ -135,7 +136,7 @@ ao_lisp_lambda_eval(void) int args_wanted; int args_provided; int f; - struct ao_lisp_cons *vals + struct ao_lisp_cons *vals; DBGI("lambda "); DBG_POLY(ao_lisp_lambda_poly(lambda)); DBG("\n"); @@ -161,6 +162,10 @@ ao_lisp_lambda_eval(void) args = ao_lisp_poly_cons(ao_lisp_arg(code, 0)); vals = ao_lisp_poly_cons(cons->cdr); + next_frame->prev = lambda->frame; + ao_lisp_frame_current = next_frame; + ao_lisp_stack->frame = ao_lisp_frame_poly(ao_lisp_frame_current); + switch (lambda->args) { case AO_LISP_FUNC_LAMBDA: for (f = 0; f < args_wanted; f++) { @@ -171,6 +176,7 @@ ao_lisp_lambda_eval(void) vals = ao_lisp_poly_cons(vals->cdr); } ao_lisp_cons_free(cons); + cons = NULL; break; case AO_LISP_FUNC_LEXPR: case AO_LISP_FUNC_NLAMBDA: @@ -182,15 +188,15 @@ ao_lisp_lambda_eval(void) args = ao_lisp_poly_cons(args->cdr); vals = ao_lisp_poly_cons(vals->cdr); } - DBGI("bind "); DBG_POLY(args->car); DBG(" = "); DBG_POLY(); DBG("\n"); + DBGI("bind "); DBG_POLY(args->car); DBG(" = "); DBG_POLY(ao_lisp_cons_poly(vals)); DBG("\n"); next_frame->vals[f].atom = args->car; next_frame->vals[f].val = ao_lisp_cons_poly(vals); break; + default: + break; } - next_frame->prev = lambda->frame; DBGI("eval frame: "); DBG_POLY(ao_lisp_frame_poly(next_frame)); DBG("\n"); - ao_lisp_frame_current = next_frame; - ao_lisp_stack->frame = ao_lisp_frame_poly(ao_lisp_frame_current); DBG_STACK(); - return ao_lisp_arg(code, 1); + DBGI("eval code: "); DBG_POLY(code->cdr); DBG("\n"); + return code->cdr; } -- cgit v1.2.3 From 9126ae10b3c5acf0055caa31b1f08215675af784 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 17 Nov 2016 16:51:34 -0800 Subject: altos/lisp: Take advantage of implicit progn in ROM code Signed-off-by: Keith Packard --- src/lisp/ao_lisp_const.lisp | 87 +++++++++++++++++---------------------------- 1 file changed, 33 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp_const.lisp b/src/lisp/ao_lisp_const.lisp index 13bb8139..3c8fd21b 100644 --- a/src/lisp/ao_lisp_const.lisp +++ b/src/lisp/ao_lisp_const.lisp @@ -46,20 +46,11 @@ (list def name - (list - 'lambda - args - (cond (exprs - (cond ((cdr exprs) - (cons progn exprs)) - ((car exprs)) - ) - ) - ) - ) + (cons 'lambda (cons args exprs)) ) ) ) + ; basic list accessors @@ -98,69 +89,58 @@ (def let (macro (vars exprs) ((lambda (make-names make-exprs make-nils) - (progn ; ; make the list of names in the let ; - (setq make-names (lambda (vars) - (cond (vars - (cons (car (car vars)) - (make-names (cdr vars)))) - ) - ) - ) + (setq make-names (lambda (vars) + (cond (vars + (cons (car (car vars)) + (make-names (cdr vars)))) + ) + ) + ) ; the set of expressions is ; the list of set expressions ; pre-pended to the ; expressions to evaluate - (setq make-exprs (lambda (vars exprs) - (progn - (cond (vars (cons - (list set - (list quote - (car (car vars)) - ) - (cadr (car vars)) - ) - (make-exprs (cdr vars) exprs) - ) - ) - (exprs) - ) - ) - ) - ) + (setq make-exprs (lambda (vars exprs) + (cond (vars (cons + (list set + (list quote + (car (car vars)) + ) + (cadr (car vars)) + ) + (make-exprs (cdr vars) exprs) + ) + ) + (exprs) + ) + ) + ) ; the parameters to the lambda is a list ; of nils of the right length - (setq make-nils (lambda (vars) - (cond (vars (cons nil (make-nils (cdr vars)))) - ) - ) - ) + (setq make-nils (lambda (vars) + (cond (vars (cons nil (make-nils (cdr vars)))) + ) + ) + ) ; prepend the set operations ; to the expressions - (setq exprs (make-exprs vars exprs)) + (setq exprs (make-exprs vars exprs)) ; build the lambda. - (cons - (list - 'lambda - (make-names vars) - (cond ((cdr exprs) (cons 'progn exprs)) - ((car exprs)) - ) - ) - (make-nils vars) - ) - ) + (cons (cons 'lambda (cons (make-names vars) exprs)) + (make-nils vars) + ) ) () () @@ -202,4 +182,3 @@ ; execute to resolve macros (and t nil) - -- cgit v1.2.3 From 11c79167cdd56015bbd1645db2d4394dcb4f0fbb Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 17 Nov 2016 16:52:30 -0800 Subject: altos/lisp: have 'while' return the last body value Instead of always returning 'nil', let while return the last body value. Signed-off-by: Keith Packard --- src/lisp/ao_lisp_error.c | 39 +++++++++++++++++++++++---------------- src/lisp/ao_lisp_eval.c | 5 +++++ 2 files changed, 28 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp_error.c b/src/lisp/ao_lisp_error.c index 7ad7b2b5..937739e9 100644 --- a/src/lisp/ao_lisp_error.c +++ b/src/lisp/ao_lisp_error.c @@ -16,23 +16,30 @@ #include static void -ao_lisp_error_cons(char *name, struct ao_lisp_cons *cons) +ao_lisp_error_poly(char *name, ao_poly poly) { int first = 1; printf("\t\t%s(", name); - if (cons) { - while (cons) { - if (!first) - printf("\t\t "); - else - first = 0; - ao_lisp_poly_print(cons->car); - printf("\n"); - cons = ao_lisp_poly_cons(cons->cdr); - } - printf("\t\t )\n"); - } else - printf(")\n"); + if (ao_lisp_poly_type(poly) == AO_LISP_CONS) { + struct ao_lisp_cons *cons = ao_lisp_poly_cons(poly); + + if (cons) { + while (cons) { + if (!first) + printf("\t\t "); + else + first = 0; + ao_lisp_poly_print(cons->car); + printf("\n"); + cons = ao_lisp_poly_cons(cons->cdr); + } + printf("\t\t )\n"); + } else + printf(")\n"); + } else { + ao_lisp_poly_print(poly); + printf("\n"); + } } static void tabs(int indent) @@ -87,8 +94,8 @@ ao_lisp_stack_print(void) printf("\t\texpr: "); ao_lisp_poly_print(s->list); printf("\n"); printf("\t\tstate: %s\n", state_names[s->state]); // printf("\t\tmacro: %s\n", s->macro ? "true" : "false"); - ao_lisp_error_cons ("sexprs: ", ao_lisp_poly_cons(s->sexprs)); - ao_lisp_error_cons ("values: ", ao_lisp_poly_cons(s->values)); + ao_lisp_error_poly ("sexprs: ", s->sexprs); + ao_lisp_error_poly ("values: ", s->values); ao_lisp_error_frame(2, "frame: ", ao_lisp_poly_frame(s->frame)); // ao_lisp_error_frame(2, "mframe: ", ao_lisp_poly_frame(s->macro_frame)); printf("\t]\n"); diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index 5fa9e0ad..ef521605 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -525,6 +525,7 @@ ao_lisp_eval_while(void) DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n"); + ao_lisp_stack->values = ao_lisp_v; if (!ao_lisp_stack->sexprs) { ao_lisp_v = AO_LISP_NIL; ao_lisp_stack->state = eval_val; @@ -548,6 +549,7 @@ ao_lisp_eval_while_test(void) DBGI(".. saved frame "); DBG_POLY(ao_lisp_stack->frame); DBG("\n"); if (ao_lisp_v) { + ao_lisp_stack->values = ao_lisp_v; ao_lisp_v = ao_lisp_poly_cons(ao_lisp_stack->sexprs)->cdr; ao_lisp_stack->state = eval_while; if (!ao_lisp_stack_push()) @@ -556,7 +558,10 @@ ao_lisp_eval_while_test(void) ao_lisp_stack->sexprs = ao_lisp_v; } else + { ao_lisp_stack->state = eval_val; + ao_lisp_v = ao_lisp_stack->values; + } return 1; } -- cgit v1.2.3 From 2cc8ca2b781be0a6e7ce14405eb4611bc00a3a3e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 17 Nov 2016 18:45:31 -0800 Subject: altos/lisp: Take advantage of implicit progns in hanoi demo Remove extra progn wrappers now that cond, lambda and while all support implicit ones. Signed-off-by: Keith Packard --- src/test/hanoi.lisp | 50 ++++++++++++++++---------------------------------- 1 file changed, 16 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/test/hanoi.lisp b/src/test/hanoi.lisp index d8ff2c86..b5f2d0f5 100644 --- a/src/test/hanoi.lisp +++ b/src/test/hanoi.lisp @@ -43,18 +43,16 @@ (defun display-stack (x y clear stack) (cond ((= 0 clear) - (cond (stack (progn - (display-string x y (car stack)) - (display-stack x (1+ y) 0 (cdr stack)) - ) - ) + (cond (stack + (display-string x y (car stack)) + (display-stack x (1+ y) 0 (cdr stack)) + ) ) ) - (t (progn - (display-string x y " ") - (display-stack x (1+ y) (1- clear) stack) - ) - ) + (t + (display-string x y " ") + (display-stack x (1+ y) (1- clear) stack) + ) ) ) @@ -68,10 +66,9 @@ ; Display all of the stacks, spaced 20 columns apart (defun display-stacks (x y stacks) - (cond (stacks (progn - (display-stack x 0 (stack-pos y (car stacks)) (car stacks)) - (display-stacks (+ x 20) y (cdr stacks))) - ) + (cond (stacks + (display-stack x 0 (stack-pos y (car stacks)) (car stacks)) + (display-stacks (+ x 20) y (cdr stacks))) ) ) @@ -132,16 +129,12 @@ (defun _hanoi (n from to use) (cond ((= 1 n) - (progn - (move-piece from to) - nil) + (move-piece from to) ) (t - (progn - (_hanoi (1- n) from use to) - (_hanoi 1 from to use) - (_hanoi (1- n) use to from) - ) + (_hanoi (1- n) from use to) + (_hanoi 1 from to use) + (_hanoi (1- n) use to from) ) ) ) @@ -155,16 +148,5 @@ (setq len (reset-stacks)) (clear) (_hanoi len 0 1 2) - ) - - ; Run many in a row to time them - -(defun hanois(n) - (cond ((> n 0) - (progn - (hanoi) - (hanois (1- n)) - ) - ) - ) + (move-to 0 23) ) -- cgit v1.2.3 From e600fc409c577eec02af612a36431c477a9c875e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 18 Nov 2016 19:04:05 -0800 Subject: altos/lisp: Add continuations This provides call/cc and makes 'stacks' visible to the application. Signed-off-by: Keith Packard --- src/lisp/Makefile | 1 + src/lisp/ao_lisp.h | 77 +++++++++--- src/lisp/ao_lisp_builtin.c | 6 +- src/lisp/ao_lisp_error.c | 82 +++++-------- src/lisp/ao_lisp_eval.c | 151 ++++------------------- src/lisp/ao_lisp_frame.c | 44 ++++--- src/lisp/ao_lisp_lambda.c | 3 +- src/lisp/ao_lisp_make_const.c | 3 +- src/lisp/ao_lisp_mem.c | 28 +++++ src/lisp/ao_lisp_poly.c | 4 + src/lisp/ao_lisp_stack.c | 279 ++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 461 insertions(+), 217 deletions(-) create mode 100644 src/lisp/ao_lisp_stack.c (limited to 'src') diff --git a/src/lisp/Makefile b/src/lisp/Makefile index 15297999..dd5a0cb4 100644 --- a/src/lisp/Makefile +++ b/src/lisp/Makefile @@ -21,6 +21,7 @@ SRCS=\ ao_lisp_eval.c \ ao_lisp_rep.c \ ao_lisp_save.c \ + ao_lisp_stack.c \ ao_lisp_error.c OBJS=$(SRCS:.c=.o) diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index bcefbabf..a8e1715a 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -75,6 +75,7 @@ extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST]; #define _ao_lisp_atom_eof _atom("eof") #define _ao_lisp_atom_save _atom("save") #define _ao_lisp_atom_restore _atom("restore") +#define _ao_lisp_atom_call2fcc _atom("call/cc") #else #include "ao_lisp_const.h" #ifndef AO_LISP_POOL @@ -99,7 +100,11 @@ extern uint8_t ao_lisp_pool[AO_LISP_POOL + AO_LISP_POOL_EXTRA]; #define AO_LISP_BUILTIN 5 #define AO_LISP_FRAME 6 #define AO_LISP_LAMBDA 7 -#define AO_LISP_NUM_TYPE 8 +#define AO_LISP_STACK 8 +#define AO_LISP_NUM_TYPE 9 + +/* Leave two bits for types to use as they please */ +#define AO_LISP_OTHER_TYPE_MASK 0x3f #define AO_LISP_NIL 0 @@ -153,22 +158,17 @@ struct ao_lisp_val { struct ao_lisp_frame { uint8_t type; - uint8_t _num; + uint8_t num; ao_poly prev; struct ao_lisp_val vals[]; }; -#define AO_LISP_FRAME_NUM_MASK 0x7f - -/* Set when the frame escapes the lambda */ +/* Set on type when the frame escapes the lambda */ #define AO_LISP_FRAME_MARK 0x80 - -static inline int ao_lisp_frame_num(struct ao_lisp_frame *f) { - return f->_num & AO_LISP_FRAME_NUM_MASK; -} +#define AO_LISP_FRAME_PRINT 0x40 static inline int ao_lisp_frame_marked(struct ao_lisp_frame *f) { - return f->_num & AO_LISP_FRAME_MARK; + return f->type & AO_LISP_FRAME_MARK; } static inline struct ao_lisp_frame * @@ -195,6 +195,7 @@ enum eval_state { }; struct ao_lisp_stack { + uint8_t type; /* AO_LISP_STACK */ uint8_t state; /* enum eval_state */ ao_poly prev; /* previous stack frame */ ao_poly sexprs; /* expressions to evaluate */ @@ -204,6 +205,17 @@ struct ao_lisp_stack { ao_poly list; /* most recent function call */ }; +#define AO_LISP_STACK_MARK 0x80 /* set on type when a reference has been taken */ +#define AO_LISP_STACK_PRINT 0x40 /* stack is being printed */ + +static inline int ao_lisp_stack_marked(struct ao_lisp_stack *s) { + return s->type & AO_LISP_STACK_MARK; +} + +static inline void ao_lisp_stack_mark(struct ao_lisp_stack *s) { + s->type |= AO_LISP_STACK_MARK; +} + static inline struct ao_lisp_stack * ao_lisp_poly_stack(ao_poly p) { @@ -216,8 +228,6 @@ ao_lisp_stack_poly(struct ao_lisp_stack *stack) return ao_lisp_poly(stack, AO_LISP_OTHER); } -extern struct ao_lisp_stack *ao_lisp_stack; -extern struct ao_lisp_stack *ao_lisp_stack_free_list; extern ao_poly ao_lisp_v; #define AO_LISP_FUNC_LAMBDA 0 @@ -276,6 +286,7 @@ enum ao_lisp_builtin_id { builtin_led, builtin_save, builtin_restore, + builtin_call_cc, _builtin_last }; @@ -315,7 +326,7 @@ ao_lisp_poly_other(ao_poly poly) { static inline uint8_t ao_lisp_other_type(void *other) { - return *((uint8_t *) other); + return *((uint8_t *) other) & AO_LISP_OTHER_TYPE_MASK; } static inline ao_poly @@ -455,6 +466,12 @@ ao_lisp_string_stash(int id, char *string); char * ao_lisp_string_fetch(int id); +void +ao_lisp_stack_stash(int id, struct ao_lisp_stack *stack); + +struct ao_lisp_stack * +ao_lisp_stack_fetch(int id); + void ao_lisp_poly_stash(int id, ao_poly poly); @@ -617,6 +634,8 @@ ao_lisp_frame_print(ao_poly p); /* lambda */ extern const struct ao_lisp_type ao_lisp_lambda_type; +extern const char *ao_lisp_state_names[]; + struct ao_lisp_lambda * ao_lisp_lambda_new(ao_poly cons); @@ -646,12 +665,40 @@ ao_lisp_save(struct ao_lisp_cons *cons); ao_poly ao_lisp_restore(struct ao_lisp_cons *cons); -/* error */ +/* stack */ extern const struct ao_lisp_type ao_lisp_stack_type; +extern struct ao_lisp_stack *ao_lisp_stack; +extern struct ao_lisp_stack *ao_lisp_stack_free_list; + +void +ao_lisp_stack_reset(struct ao_lisp_stack *stack); + +int +ao_lisp_stack_push(void); + +void +ao_lisp_stack_pop(void); + +void +ao_lisp_stack_clear(void); + +void +ao_lisp_stack_print(ao_poly stack); + +ao_poly +ao_lisp_stack_eval(void); + +ao_poly +ao_lisp_call_cc(struct ao_lisp_cons *cons); + +/* error */ + +void +ao_lisp_error_poly(char *name, ao_poly poly, ao_poly last); void -ao_lisp_stack_print(void); +ao_lisp_error_frame(int indent, char *name, struct ao_lisp_frame *frame); ao_poly ao_lisp_error(int error, char *format, ...); diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index 6cbcb92c..4c845307 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -86,6 +86,7 @@ static const ao_poly builtin_names[] = { [builtin_led] = _ao_lisp_atom_led, [builtin_save] = _ao_lisp_atom_save, [builtin_restore] = _ao_lisp_atom_restore, + [builtin_call_cc] = _ao_lisp_atom_call2fcc, }; @@ -117,9 +118,7 @@ void ao_lisp_builtin_print(ao_poly b) { struct ao_lisp_builtin *builtin = ao_lisp_poly_builtin(b); - printf("[builtin %s %s]", - ao_lisp_args_name(builtin->args), - ao_lisp_builtin_name(builtin->func)); + printf("%s", ao_lisp_builtin_name(builtin->func)); } ao_poly @@ -599,5 +598,6 @@ const ao_lisp_func_t ao_lisp_builtins[] = { [builtin_delay] = ao_lisp_delay, [builtin_save] = ao_lisp_save, [builtin_restore] = ao_lisp_restore, + [builtin_call_cc] = ao_lisp_call_cc, }; diff --git a/src/lisp/ao_lisp_error.c b/src/lisp/ao_lisp_error.c index 937739e9..54a9be10 100644 --- a/src/lisp/ao_lisp_error.c +++ b/src/lisp/ao_lisp_error.c @@ -15,23 +15,24 @@ #include "ao_lisp.h" #include -static void -ao_lisp_error_poly(char *name, ao_poly poly) +void +ao_lisp_error_poly(char *name, ao_poly poly, ao_poly last) { int first = 1; printf("\t\t%s(", name); if (ao_lisp_poly_type(poly) == AO_LISP_CONS) { - struct ao_lisp_cons *cons = ao_lisp_poly_cons(poly); - - if (cons) { - while (cons) { + if (poly) { + while (poly) { + struct ao_lisp_cons *cons = ao_lisp_poly_cons(poly); if (!first) printf("\t\t "); else first = 0; ao_lisp_poly_print(cons->car); printf("\n"); - cons = ao_lisp_poly_cons(cons->cdr); + if (poly == last) + break; + poly = cons->cdr; } printf("\t\t )\n"); } else @@ -48,7 +49,7 @@ static void tabs(int indent) printf("\t"); } -static void +void ao_lisp_error_frame(int indent, char *name, struct ao_lisp_frame *frame) { int f; @@ -56,51 +57,30 @@ ao_lisp_error_frame(int indent, char *name, struct ao_lisp_frame *frame) tabs(indent); printf ("%s{", name); if (frame) { - for (f = 0; f < ao_lisp_frame_num(frame); f++) { - if (f != 0) { - tabs(indent); - printf(" "); + if (frame->type & AO_LISP_FRAME_PRINT) + printf("recurse..."); + else { + frame->type |= AO_LISP_FRAME_PRINT; + for (f = 0; f < frame->num; f++) { + if (f != 0) { + tabs(indent); + printf(" "); + } + ao_lisp_poly_print(frame->vals[f].atom); + printf(" = "); + ao_lisp_poly_print(frame->vals[f].val); + printf("\n"); } - ao_lisp_poly_print(frame->vals[f].atom); - printf(" = "); - ao_lisp_poly_print(frame->vals[f].val); - printf("\n"); + if (frame->prev) + ao_lisp_error_frame(indent + 1, "prev: ", ao_lisp_poly_frame(frame->prev)); + frame->type &= ~AO_LISP_FRAME_PRINT; } - if (frame->prev) - ao_lisp_error_frame(indent + 1, "prev: ", ao_lisp_poly_frame(frame->prev)); - } - tabs(indent); - printf(" }\n"); + tabs(indent); + printf(" }\n"); + } else + printf ("}\n"); } -static const char *state_names[] = { - "sexpr", - "val", - "formal", - "exec", - "cond", - "cond_test", - "progn", -}; - -void -ao_lisp_stack_print(void) -{ - struct ao_lisp_stack *s; - printf("Value: "); ao_lisp_poly_print(ao_lisp_v); printf("\n"); - printf("Stack:\n"); - for (s = ao_lisp_stack; s; s = ao_lisp_poly_stack(s->prev)) { - printf("\t[\n"); - printf("\t\texpr: "); ao_lisp_poly_print(s->list); printf("\n"); - printf("\t\tstate: %s\n", state_names[s->state]); -// printf("\t\tmacro: %s\n", s->macro ? "true" : "false"); - ao_lisp_error_poly ("sexprs: ", s->sexprs); - ao_lisp_error_poly ("values: ", s->values); - ao_lisp_error_frame(2, "frame: ", ao_lisp_poly_frame(s->frame)); -// ao_lisp_error_frame(2, "mframe: ", ao_lisp_poly_frame(s->macro_frame)); - printf("\t]\n"); - } -} ao_poly ao_lisp_error(int error, char *format, ...) @@ -112,7 +92,9 @@ ao_lisp_error(int error, char *format, ...) vprintf(format, args); va_end(args); printf("\n"); - ao_lisp_stack_print(); + printf("Value: "); ao_lisp_poly_print(ao_lisp_v); printf("\n"); + printf("Stack:\n"); + ao_lisp_stack_print(ao_lisp_stack_poly(ao_lisp_stack)); printf("Globals:\n\t"); ao_lisp_frame_print(ao_lisp_frame_poly(ao_lisp_frame_global)); printf("\n"); diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index ef521605..2460a32a 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -16,68 +16,9 @@ #include "ao_lisp.h" #include -const struct ao_lisp_type ao_lisp_stack_type; - -static int -stack_size(void *addr) -{ - (void) addr; - return sizeof (struct ao_lisp_stack); -} - -static void -stack_mark(void *addr) -{ - struct ao_lisp_stack *stack = addr; - for (;;) { - ao_lisp_poly_mark(stack->sexprs, 0); - ao_lisp_poly_mark(stack->values, 0); - /* no need to mark values_tail */ - ao_lisp_poly_mark(stack->frame, 0); - ao_lisp_poly_mark(stack->list, 0); - stack = ao_lisp_poly_stack(stack->prev); - if (ao_lisp_mark_memory(&ao_lisp_stack_type, stack)) - break; - } -} - -static void -stack_move(void *addr) -{ - struct ao_lisp_stack *stack = addr; - - while (stack) { - struct ao_lisp_stack *prev; - int ret; - (void) ao_lisp_poly_move(&stack->sexprs, 0); - (void) ao_lisp_poly_move(&stack->values, 0); - (void) ao_lisp_poly_move(&stack->values_tail, 0); - (void) ao_lisp_poly_move(&stack->frame, 0); - (void) ao_lisp_poly_move(&stack->list, 0); - prev = ao_lisp_poly_stack(stack->prev); - if (!prev) - break; - ret = ao_lisp_move_memory(&ao_lisp_stack_type, (void **) &prev); - if (prev != ao_lisp_poly_stack(stack->prev)) - stack->prev = ao_lisp_stack_poly(prev); - if (ret) - break; - stack = prev; - } -} - -const struct ao_lisp_type ao_lisp_stack_type = { - .size = stack_size, - .mark = stack_mark, - .move = stack_move, - .name = "stack" -}; - struct ao_lisp_stack *ao_lisp_stack; ao_poly ao_lisp_v; -struct ao_lisp_stack *ao_lisp_stack_free_list; - ao_poly ao_lisp_set_cond(struct ao_lisp_cons *c) { @@ -86,72 +27,6 @@ ao_lisp_set_cond(struct ao_lisp_cons *c) return AO_LISP_NIL; } -static void -ao_lisp_stack_reset(struct ao_lisp_stack *stack) -{ - stack->state = eval_sexpr; - stack->sexprs = AO_LISP_NIL; - stack->values = AO_LISP_NIL; - stack->values_tail = AO_LISP_NIL; -} - - -static int -ao_lisp_stack_push(void) -{ - struct ao_lisp_stack *stack; - if (ao_lisp_stack_free_list) { - stack = ao_lisp_stack_free_list; - ao_lisp_stack_free_list = ao_lisp_poly_stack(stack->prev); - } else { - stack = ao_lisp_alloc(sizeof (struct ao_lisp_stack)); - if (!stack) - return 0; - } - stack->prev = ao_lisp_stack_poly(ao_lisp_stack); - stack->frame = ao_lisp_frame_poly(ao_lisp_frame_current); - stack->list = AO_LISP_NIL; - ao_lisp_stack = stack; - ao_lisp_stack_reset(stack); - DBGI("stack push\n"); - DBG_FRAMES(); - DBG_IN(); - return 1; -} - -static void -ao_lisp_stack_pop(void) -{ - ao_poly prev; - struct ao_lisp_frame *prev_frame; - - if (!ao_lisp_stack) - return; - prev = ao_lisp_stack->prev; - ao_lisp_stack->prev = ao_lisp_stack_poly(ao_lisp_stack_free_list); - ao_lisp_stack_free_list = ao_lisp_stack; - - ao_lisp_stack = ao_lisp_poly_stack(prev); - prev_frame = ao_lisp_frame_current; - if (ao_lisp_stack) - ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->frame); - else - ao_lisp_frame_current = NULL; - if (ao_lisp_frame_current != prev_frame) - ao_lisp_frame_free(prev_frame); - DBG_OUT(); - DBGI("stack pop\n"); - DBG_FRAMES(); -} - -static void -ao_lisp_stack_clear(void) -{ - ao_lisp_stack = NULL; - ao_lisp_frame_current = NULL; - ao_lisp_v = AO_LISP_NIL; -} - static int func_type(ao_poly func) { @@ -162,6 +37,8 @@ func_type(ao_poly func) return ao_lisp_poly_builtin(func)->args & AO_LISP_FUNC_MASK; case AO_LISP_LAMBDA: return ao_lisp_poly_lambda(func)->args; + case AO_LISP_STACK: + return AO_LISP_FUNC_LAMBDA; default: ao_lisp_error(AO_LISP_INVALID, "not a func"); return -1; @@ -392,10 +269,12 @@ ao_lisp_eval_exec(void) DBGI("set "); DBG_POLY(atom); DBG(" = "); DBG_POLY(val); DBG("\n"); }); builtin = ao_lisp_poly_builtin(ao_lisp_v); - if (builtin->args & AO_LISP_FUNC_FREE_ARGS) + if (builtin->args & AO_LISP_FUNC_FREE_ARGS && !ao_lisp_stack_marked(ao_lisp_stack)) ao_lisp_cons_free(ao_lisp_poly_cons(ao_lisp_stack->values)); ao_lisp_v = v; + ao_lisp_stack->values = AO_LISP_NIL; + ao_lisp_stack->values_tail = AO_LISP_NIL; DBGI(".. result "); DBG_POLY(ao_lisp_v); DBG ("\n"); DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); break; @@ -404,12 +283,18 @@ ao_lisp_eval_exec(void) ao_lisp_stack->state = eval_progn; v = ao_lisp_lambda_eval(); ao_lisp_stack->sexprs = v; + ao_lisp_stack->values = AO_LISP_NIL; + ao_lisp_stack->values_tail = AO_LISP_NIL; DBGI(".. sexprs "); DBG_POLY(ao_lisp_stack->sexprs); DBG("\n"); DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); break; + case AO_LISP_STACK: + DBGI(".. stack "); DBG_POLY(ao_lisp_v); DBG("\n"); + ao_lisp_v = ao_lisp_stack_eval(); + DBGI(".. value "); DBG_POLY(ao_lisp_v); DBG("\n"); + DBGI(".. frame "); DBG_POLY(ao_lisp_frame_poly(ao_lisp_frame_current)); DBG("\n"); + break; } - ao_lisp_stack->values = AO_LISP_NIL; - ao_lisp_stack->values_tail = AO_LISP_NIL; return 1; } @@ -599,6 +484,16 @@ static int (*const evals[])(void) = { [eval_macro] = ao_lisp_eval_macro, }; +const char *ao_lisp_state_names[] = { + "sexpr", + "val", + "formal", + "exec", + "cond", + "cond_test", + "progn", +}; + /* * Called at restore time to reset all execution state */ diff --git a/src/lisp/ao_lisp_frame.c b/src/lisp/ao_lisp_frame.c index 9d17f6fa..17fa141a 100644 --- a/src/lisp/ao_lisp_frame.c +++ b/src/lisp/ao_lisp_frame.c @@ -24,7 +24,7 @@ static int frame_size(void *addr) { struct ao_lisp_frame *frame = addr; - return frame_num_size(ao_lisp_frame_num(frame)); + return frame_num_size(frame->num); } static void @@ -37,7 +37,7 @@ frame_mark(void *addr) MDBG_MOVE("frame mark %d\n", MDBG_OFFSET(frame)); if (!AO_LISP_IS_POOL(frame)) break; - for (f = 0; f < ao_lisp_frame_num(frame); f++) { + for (f = 0; f < frame->num; f++) { struct ao_lisp_val *v = &frame->vals[f]; ao_lisp_poly_mark(v->val, 0); @@ -68,7 +68,7 @@ frame_move(void *addr) MDBG_MOVE("frame move %d\n", MDBG_OFFSET(frame)); if (!AO_LISP_IS_POOL(frame)) break; - for (f = 0; f < ao_lisp_frame_num(frame); f++) { + for (f = 0; f < frame->num; f++) { struct ao_lisp_val *v = &frame->vals[f]; ao_lisp_poly_move(&v->atom, 0); @@ -109,15 +109,21 @@ ao_lisp_frame_print(ao_poly p) printf ("{"); if (frame) { - for (f = 0; f < ao_lisp_frame_num(frame); f++) { - if (f != 0) - printf(", "); - ao_lisp_poly_print(frame->vals[f].atom); - printf(" = "); - ao_lisp_poly_print(frame->vals[f].val); + if (frame->type & AO_LISP_FRAME_PRINT) + printf("recurse..."); + else { + frame->type |= AO_LISP_FRAME_PRINT; + for (f = 0; f < frame->num; f++) { + if (f != 0) + printf(", "); + ao_lisp_poly_print(frame->vals[f].atom); + printf(" = "); + ao_lisp_poly_print(frame->vals[f].val); + } + if (frame->prev) + ao_lisp_poly_print(frame->prev); + frame->type &= ~AO_LISP_FRAME_PRINT; } - if (frame->prev) - ao_lisp_poly_print(frame->prev); } printf("}"); } @@ -126,7 +132,7 @@ ao_poly * ao_lisp_frame_ref(struct ao_lisp_frame *frame, ao_poly atom) { int f; - for (f = 0; f < ao_lisp_frame_num(frame); f++) + for (f = 0; f < frame->num; f++) if (frame->vals[f].atom == atom) return &frame->vals[f].val; return NULL; @@ -175,7 +181,7 @@ ao_lisp_frame_new(int num) return NULL; } frame->type = AO_LISP_FRAME; - frame->_num = num; + frame->num = num; frame->prev = AO_LISP_NIL; memset(frame->vals, '\0', num * sizeof (struct ao_lisp_val)); return frame; @@ -186,7 +192,7 @@ ao_lisp_frame_mark(struct ao_lisp_frame *frame) { if (!frame) return AO_LISP_NIL; - frame->_num |= AO_LISP_FRAME_MARK; + frame->type |= AO_LISP_FRAME_MARK; return ao_lisp_frame_poly(frame); } @@ -194,7 +200,7 @@ void ao_lisp_frame_free(struct ao_lisp_frame *frame) { if (!ao_lisp_frame_marked(frame)) { - int num = ao_lisp_frame_num(frame); + int num = frame->num; if (num < AO_LISP_FRAME_FREE) { frame->prev = ao_lisp_frame_poly(ao_lisp_frame_free_list[num]); ao_lisp_frame_free_list[num] = frame; @@ -209,7 +215,7 @@ ao_lisp_frame_realloc(struct ao_lisp_frame **frame_ref, int new_num) struct ao_lisp_frame *new; int copy; - if (new_num == ao_lisp_frame_num(frame)) + if (new_num == frame->num) return frame; new = ao_lisp_frame_new(new_num); if (!new) @@ -220,8 +226,8 @@ ao_lisp_frame_realloc(struct ao_lisp_frame **frame_ref, int new_num) */ frame = *frame_ref; copy = new_num; - if (copy > ao_lisp_frame_num(frame)) - copy = ao_lisp_frame_num(frame); + if (copy > frame->num) + copy = frame->num; memcpy(new->vals, frame->vals, copy * sizeof (struct ao_lisp_val)); new->prev = frame->prev; ao_lisp_frame_free(frame); @@ -239,7 +245,7 @@ ao_lisp_frame_add(struct ao_lisp_frame **frame_ref, ao_poly atom, ao_poly val) ao_lisp_poly_stash(0, atom); ao_lisp_poly_stash(1, val); if (frame) { - f = ao_lisp_frame_num(frame); + f = frame->num; frame = ao_lisp_frame_realloc(frame_ref, f + 1); } else { f = 0; diff --git a/src/lisp/ao_lisp_lambda.c b/src/lisp/ao_lisp_lambda.c index e2053a6f..656936cb 100644 --- a/src/lisp/ao_lisp_lambda.c +++ b/src/lisp/ao_lisp_lambda.c @@ -175,7 +175,8 @@ ao_lisp_lambda_eval(void) args = ao_lisp_poly_cons(args->cdr); vals = ao_lisp_poly_cons(vals->cdr); } - ao_lisp_cons_free(cons); + if (!ao_lisp_stack_marked(ao_lisp_stack)) + ao_lisp_cons_free(cons); cons = NULL; break; case AO_LISP_FUNC_LEXPR: diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index 495e48cd..de9c5725 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -71,6 +71,7 @@ struct builtin_func funcs[] = { { .name = "led", .args = AO_LISP_FUNC_F_LEXPR, .func = builtin_led }, { .name = "save", .args = AO_LISP_FUNC_F_LAMBDA, .func = builtin_save }, { .name = "restore", .args = AO_LISP_FUNC_F_LAMBDA, .func = builtin_restore }, + { .name = "call/cc", .args = AO_LISP_FUNC_F_LAMBDA, .func = builtin_call_cc }, }; #define N_FUNC (sizeof funcs / sizeof funcs[0]) @@ -358,7 +359,7 @@ main(int argc, char **argv) /* Reduce to referenced values */ ao_lisp_collect(AO_LISP_COLLECT_FULL); - for (f = 0; f < ao_lisp_frame_num(ao_lisp_frame_global); f++) { + for (f = 0; f < ao_lisp_frame_global->num; f++) { val = ao_has_macro(ao_lisp_frame_global->vals[f].val); if (val != AO_LISP_NIL) { printf("error: function %s contains unresolved macro: ", diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 12a5ba55..0dfad1d7 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -144,6 +144,7 @@ struct ao_lisp_root { static struct ao_lisp_cons *save_cons[2]; static char *save_string[2]; +static struct ao_lisp_stack *save_stack[3]; static ao_poly save_poly[2]; static const struct ao_lisp_root ao_lisp_root[] = { @@ -155,6 +156,18 @@ static const struct ao_lisp_root ao_lisp_root[] = { .type = &ao_lisp_cons_type, .addr = (void **) &save_cons[1], }, + { + .type = &ao_lisp_stack_type, + .addr = (void **) &save_stack[0] + }, + { + .type = &ao_lisp_stack_type, + .addr = (void **) &save_stack[1] + }, + { + .type = &ao_lisp_stack_type, + .addr = (void **) &save_stack[2] + }, { .type = &ao_lisp_string_type, .addr = (void **) &save_string[0] @@ -434,6 +447,7 @@ static const struct ao_lisp_type const *ao_lisp_types[AO_LISP_NUM_TYPE] = { [AO_LISP_BUILTIN] = &ao_lisp_builtin_type, [AO_LISP_FRAME] = &ao_lisp_frame_type, [AO_LISP_LAMBDA] = &ao_lisp_lambda_type, + [AO_LISP_STACK] = &ao_lisp_stack_type, }; static int @@ -818,6 +832,20 @@ ao_lisp_cons_fetch(int id) return cons; } +void +ao_lisp_stack_stash(int id, struct ao_lisp_stack *stack) +{ + save_stack[id] = stack; +} + +struct ao_lisp_stack * +ao_lisp_stack_fetch(int id) +{ + struct ao_lisp_stack *stack = save_stack[id]; + save_stack[id] = NULL; + return stack; +} + void ao_lisp_string_stash(int id, char *string) { diff --git a/src/lisp/ao_lisp_poly.c b/src/lisp/ao_lisp_poly.c index 236176e7..800ee06d 100644 --- a/src/lisp/ao_lisp_poly.c +++ b/src/lisp/ao_lisp_poly.c @@ -54,6 +54,10 @@ static const struct ao_lisp_funcs ao_lisp_funcs[AO_LISP_NUM_TYPE] = { .print = ao_lisp_lambda_print, .patom = ao_lisp_lambda_print, }, + [AO_LISP_STACK] = { + .print = ao_lisp_stack_print, + .patom = ao_lisp_stack_print, + }, }; static const struct ao_lisp_funcs * diff --git a/src/lisp/ao_lisp_stack.c b/src/lisp/ao_lisp_stack.c new file mode 100644 index 00000000..9c773e83 --- /dev/null +++ b/src/lisp/ao_lisp_stack.c @@ -0,0 +1,279 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#define DBG_EVAL 0 +#include "ao_lisp.h" + +const struct ao_lisp_type ao_lisp_stack_type; + +static int +stack_size(void *addr) +{ + (void) addr; + return sizeof (struct ao_lisp_stack); +} + +static void +stack_mark(void *addr) +{ + struct ao_lisp_stack *stack = addr; + for (;;) { + ao_lisp_poly_mark(stack->sexprs, 0); + ao_lisp_poly_mark(stack->values, 0); + /* no need to mark values_tail */ + ao_lisp_poly_mark(stack->frame, 0); + ao_lisp_poly_mark(stack->list, 0); + stack = ao_lisp_poly_stack(stack->prev); + if (ao_lisp_mark_memory(&ao_lisp_stack_type, stack)) + break; + } +} + +static void +stack_move(void *addr) +{ + struct ao_lisp_stack *stack = addr; + + while (stack) { + struct ao_lisp_stack *prev; + int ret; + (void) ao_lisp_poly_move(&stack->sexprs, 0); + (void) ao_lisp_poly_move(&stack->values, 0); + (void) ao_lisp_poly_move(&stack->values_tail, 0); + (void) ao_lisp_poly_move(&stack->frame, 0); + (void) ao_lisp_poly_move(&stack->list, 0); + prev = ao_lisp_poly_stack(stack->prev); + if (!prev) + break; + ret = ao_lisp_move_memory(&ao_lisp_stack_type, (void **) &prev); + if (prev != ao_lisp_poly_stack(stack->prev)) + stack->prev = ao_lisp_stack_poly(prev); + if (ret) + break; + stack = prev; + } +} + +const struct ao_lisp_type ao_lisp_stack_type = { + .size = stack_size, + .mark = stack_mark, + .move = stack_move, + .name = "stack" +}; + +struct ao_lisp_stack *ao_lisp_stack_free_list; + +void +ao_lisp_stack_reset(struct ao_lisp_stack *stack) +{ + stack->state = eval_sexpr; + stack->sexprs = AO_LISP_NIL; + stack->values = AO_LISP_NIL; + stack->values_tail = AO_LISP_NIL; +} + +static struct ao_lisp_stack * +ao_lisp_stack_new(void) +{ + struct ao_lisp_stack *stack; + + if (ao_lisp_stack_free_list) { + stack = ao_lisp_stack_free_list; + ao_lisp_stack_free_list = ao_lisp_poly_stack(stack->prev); + } else { + stack = ao_lisp_alloc(sizeof (struct ao_lisp_stack)); + if (!stack) + return 0; + stack->type = AO_LISP_STACK; + } + ao_lisp_stack_reset(stack); + return stack; +} + +int +ao_lisp_stack_push(void) +{ + struct ao_lisp_stack *stack = ao_lisp_stack_new(); + + if (!stack) + return 0; + + stack->prev = ao_lisp_stack_poly(ao_lisp_stack); + stack->frame = ao_lisp_frame_poly(ao_lisp_frame_current); + stack->list = AO_LISP_NIL; + + ao_lisp_stack = stack; + + DBGI("stack push\n"); + DBG_FRAMES(); + DBG_IN(); + return 1; +} + +void +ao_lisp_stack_pop(void) +{ + ao_poly prev; + struct ao_lisp_frame *prev_frame; + + if (!ao_lisp_stack) + return; + prev = ao_lisp_stack->prev; + if (!ao_lisp_stack_marked(ao_lisp_stack)) { + ao_lisp_stack->prev = ao_lisp_stack_poly(ao_lisp_stack_free_list); + ao_lisp_stack_free_list = ao_lisp_stack; + } + + ao_lisp_stack = ao_lisp_poly_stack(prev); + prev_frame = ao_lisp_frame_current; + if (ao_lisp_stack) + ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->frame); + else + ao_lisp_frame_current = NULL; + if (ao_lisp_frame_current != prev_frame) + ao_lisp_frame_free(prev_frame); + DBG_OUT(); + DBGI("stack pop\n"); + DBG_FRAMES(); +} + +void +ao_lisp_stack_clear(void) +{ + ao_lisp_stack = NULL; + ao_lisp_frame_current = NULL; + ao_lisp_v = AO_LISP_NIL; +} + +void +ao_lisp_stack_print(ao_poly poly) +{ + struct ao_lisp_stack *s = ao_lisp_poly_stack(poly); + + if (s->type & AO_LISP_STACK_PRINT) { + printf("[recurse...]"); + return; + } + while (s) { + s->type |= AO_LISP_STACK_PRINT; + printf("\t[\n"); + printf("\t\texpr: "); ao_lisp_poly_print(s->list); printf("\n"); + printf("\t\tstate: %s\n", ao_lisp_state_names[s->state]); + ao_lisp_error_poly ("values: ", s->values, s->values_tail); + ao_lisp_error_poly ("sexprs: ", s->sexprs, AO_LISP_NIL); + ao_lisp_error_frame(2, "frame: ", ao_lisp_poly_frame(s->frame)); + printf("\t]\n"); + s->type &= ~AO_LISP_STACK_PRINT; + s = ao_lisp_poly_stack(s->prev); + } +} + +/* + * Copy a stack, being careful to keep everybody referenced + */ +static struct ao_lisp_stack * +ao_lisp_stack_copy(struct ao_lisp_stack *old) +{ + struct ao_lisp_stack *new = NULL; + struct ao_lisp_stack *n, *prev = NULL; + + while (old) { + ao_lisp_stack_stash(0, old); + ao_lisp_stack_stash(1, new); + ao_lisp_stack_stash(2, prev); + n = ao_lisp_stack_new(); + prev = ao_lisp_stack_fetch(2); + new = ao_lisp_stack_fetch(1); + old = ao_lisp_stack_fetch(0); + if (!n) + return NULL; + + ao_lisp_stack_mark(old); + ao_lisp_frame_mark(ao_lisp_poly_frame(old->frame)); + *n = *old; + + if (prev) + prev->prev = ao_lisp_stack_poly(n); + else + new = n; + prev = n; + + old = ao_lisp_poly_stack(old->prev); + } + return new; +} + +/* + * Evaluate a continuation invocation + */ +ao_poly +ao_lisp_stack_eval(void) +{ + struct ao_lisp_stack *new = ao_lisp_stack_copy(ao_lisp_poly_stack(ao_lisp_v)); + if (!new) + return AO_LISP_NIL; + + struct ao_lisp_cons *cons = ao_lisp_poly_cons(ao_lisp_stack->values); + + if (!cons || !cons->cdr) + return ao_lisp_error(AO_LISP_INVALID, "continuation requires a value"); + + new->state = eval_val; + + ao_lisp_stack = new; + ao_lisp_frame_current = ao_lisp_poly_frame(ao_lisp_stack->frame); + + return ao_lisp_poly_cons(cons->cdr)->car; +} + +/* + * Call with current continuation. This calls a lambda, passing + * it a single argument which is the current continuation + */ +ao_poly +ao_lisp_call_cc(struct ao_lisp_cons *cons) +{ + struct ao_lisp_stack *new; + ao_poly v; + + /* Make sure the single parameter is a lambda */ + if (!ao_lisp_check_argc(_ao_lisp_atom_call2fcc, cons, 1, 1)) + return AO_LISP_NIL; + if (!ao_lisp_check_argt(_ao_lisp_atom_call2fcc, cons, 0, AO_LISP_LAMBDA, 0)) + return AO_LISP_NIL; + + /* go get the lambda */ + ao_lisp_v = ao_lisp_arg(cons, 0); + + /* Note that the whole call chain now has + * a reference to it which may escape + */ + new = ao_lisp_stack_copy(ao_lisp_stack); + if (!new) + return AO_LISP_NIL; + + /* re-fetch cons after the allocation */ + cons = ao_lisp_poly_cons(ao_lisp_poly_cons(ao_lisp_stack->values)->cdr); + + /* Reset the arg list to the current stack, + * and call the lambda + */ + + cons->car = ao_lisp_stack_poly(new); + cons->cdr = AO_LISP_NIL; + v = ao_lisp_lambda_eval(); + ao_lisp_stack->sexprs = v; + ao_lisp_stack->state = eval_progn; + return AO_LISP_NIL; +} -- cgit v1.2.3 From 4c812b8c903bd7e689572f8800ecc092af9cfe18 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 18 Nov 2016 21:12:50 -0800 Subject: altos/lisp: Make DBG settings global This avoids having different values in different files, which wasn't useful. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 8 +++++++- src/lisp/ao_lisp_eval.c | 1 - src/lisp/ao_lisp_lambda.c | 1 - 3 files changed, 7 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index a8e1715a..cea834fc 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -15,6 +15,9 @@ #ifndef _AO_LISP_H_ #define _AO_LISP_H_ +#define DBG_MEM 0 +#define DBG_EVAL 0 + #include #include //#include @@ -326,6 +329,10 @@ ao_lisp_poly_other(ao_poly poly) { static inline uint8_t ao_lisp_other_type(void *other) { +#if DBG_MEM + if ((*((uint8_t *) other) & AO_LISP_OTHER_TYPE_MASK) >= AO_LISP_NUM_TYPE) + ao_lisp_abort(); +#endif return *((uint8_t *) other) & AO_LISP_OTHER_TYPE_MASK; } @@ -743,7 +750,6 @@ ao_lisp_frames_dump(void) #define DBG_FRAMES() #endif -#define DBG_MEM 0 #define DBG_MEM_START 1 #if DBG_MEM diff --git a/src/lisp/ao_lisp_eval.c b/src/lisp/ao_lisp_eval.c index 2460a32a..3be7c9c4 100644 --- a/src/lisp/ao_lisp_eval.c +++ b/src/lisp/ao_lisp_eval.c @@ -12,7 +12,6 @@ * General Public License for more details. */ -#define DBG_EVAL 0 #include "ao_lisp.h" #include diff --git a/src/lisp/ao_lisp_lambda.c b/src/lisp/ao_lisp_lambda.c index 656936cb..67ad24ee 100644 --- a/src/lisp/ao_lisp_lambda.c +++ b/src/lisp/ao_lisp_lambda.c @@ -15,7 +15,6 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#define DBG_EVAL 0 #include "ao_lisp.h" int -- cgit v1.2.3 From ecef616599d5ec4fd5d42e67d0dc779a0630079b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 18 Nov 2016 21:14:47 -0800 Subject: altos/lisp: Use poly stashes for stacks Saves some memory. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 24 +++++++++++++---------- src/lisp/ao_lisp_mem.c | 49 ++++++++++++++--------------------------------- src/lisp/ao_lisp_string.c | 2 +- 3 files changed, 29 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index cea834fc..e238d4fe 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -468,22 +468,26 @@ struct ao_lisp_cons * ao_lisp_cons_fetch(int id); void -ao_lisp_string_stash(int id, char *string); +ao_lisp_poly_stash(int id, ao_poly poly); -char * -ao_lisp_string_fetch(int id); +ao_poly +ao_lisp_poly_fetch(int id); void -ao_lisp_stack_stash(int id, struct ao_lisp_stack *stack); +ao_lisp_string_stash(int id, char *string); -struct ao_lisp_stack * -ao_lisp_stack_fetch(int id); +char * +ao_lisp_string_fetch(int id); -void -ao_lisp_poly_stash(int id, ao_poly poly); +static inline void +ao_lisp_stack_stash(int id, struct ao_lisp_stack *stack) { + ao_lisp_poly_stash(id, ao_lisp_stack_poly(stack)); +} -ao_poly -ao_lisp_poly_fetch(int id); +static inline struct ao_lisp_stack * +ao_lisp_stack_fetch(int id) { + return ao_lisp_poly_stack(ao_lisp_poly_fetch(id)); +} /* cons */ extern const struct ao_lisp_type ao_lisp_cons_type; diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 0dfad1d7..2599f719 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -144,8 +144,7 @@ struct ao_lisp_root { static struct ao_lisp_cons *save_cons[2]; static char *save_string[2]; -static struct ao_lisp_stack *save_stack[3]; -static ao_poly save_poly[2]; +static ao_poly save_poly[3]; static const struct ao_lisp_root ao_lisp_root[] = { { @@ -156,25 +155,13 @@ static const struct ao_lisp_root ao_lisp_root[] = { .type = &ao_lisp_cons_type, .addr = (void **) &save_cons[1], }, - { - .type = &ao_lisp_stack_type, - .addr = (void **) &save_stack[0] - }, - { - .type = &ao_lisp_stack_type, - .addr = (void **) &save_stack[1] - }, - { - .type = &ao_lisp_stack_type, - .addr = (void **) &save_stack[2] - }, { .type = &ao_lisp_string_type, - .addr = (void **) &save_string[0] + .addr = (void **) &save_string[0], }, { .type = &ao_lisp_string_type, - .addr = (void **) &save_string[1] + .addr = (void **) &save_string[1], }, { .type = NULL, @@ -184,6 +171,10 @@ static const struct ao_lisp_root ao_lisp_root[] = { .type = NULL, .addr = (void **) &save_poly[1] }, + { + .type = NULL, + .addr = (void **) &save_poly[2] + }, { .type = &ao_lisp_atom_type, .addr = (void **) &ao_lisp_atoms @@ -833,17 +824,17 @@ ao_lisp_cons_fetch(int id) } void -ao_lisp_stack_stash(int id, struct ao_lisp_stack *stack) +ao_lisp_poly_stash(int id, ao_poly poly) { - save_stack[id] = stack; + save_poly[id] = poly; } -struct ao_lisp_stack * -ao_lisp_stack_fetch(int id) +ao_poly +ao_lisp_poly_fetch(int id) { - struct ao_lisp_stack *stack = save_stack[id]; - save_stack[id] = NULL; - return stack; + ao_poly poly = save_poly[id]; + save_poly[id] = AO_LISP_NIL; + return poly; } void @@ -859,16 +850,4 @@ ao_lisp_string_fetch(int id) save_string[id] = NULL; return string; } -void -ao_lisp_poly_stash(int id, ao_poly poly) -{ - save_poly[id] = poly; -} -ao_poly -ao_lisp_poly_fetch(int id) -{ - ao_poly poly = save_poly[id]; - save_poly[id] = AO_LISP_NIL; - return poly; -} diff --git a/src/lisp/ao_lisp_string.c b/src/lisp/ao_lisp_string.c index 207d4f3b..cd7b27a9 100644 --- a/src/lisp/ao_lisp_string.c +++ b/src/lisp/ao_lisp_string.c @@ -104,9 +104,9 @@ ao_lisp_string_unpack(char *a) ao_lisp_cons_stash(1, tail); ao_lisp_string_stash(0, a); struct ao_lisp_cons *n = ao_lisp_cons_cons(ao_lisp_int_poly(c), NULL); + a = ao_lisp_string_fetch(0); cons = ao_lisp_cons_fetch(0); tail = ao_lisp_cons_fetch(1); - a = ao_lisp_string_fetch(0); if (!n) { cons = NULL; -- cgit v1.2.3 From 85db6d68a273859482e036b60fec7e2b84e9c262 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 18 Nov 2016 21:15:33 -0800 Subject: altos/lisp: Empty lambda body is not an error It's not very exciting, but it's still legal Signed-off-by: Keith Packard --- src/lisp/ao_lisp_lambda.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp_lambda.c b/src/lisp/ao_lisp_lambda.c index 67ad24ee..b164cd66 100644 --- a/src/lisp/ao_lisp_lambda.c +++ b/src/lisp/ao_lisp_lambda.c @@ -77,9 +77,6 @@ ao_lisp_lambda_alloc(struct ao_lisp_cons *code, int args) if (!lambda) return AO_LISP_NIL; - if (!code->cdr) - return ao_lisp_error(AO_LISP_INVALID, "missing parameters to lambda"); - if (!ao_lisp_check_argt(_ao_lisp_atom_lambda, code, 0, AO_LISP_CONS, 1)) return AO_LISP_NIL; f = 0; -- cgit v1.2.3 From 35424031747b41b1125e715a975f1679b89fc27a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 18 Nov 2016 21:16:11 -0800 Subject: altos/lisp: bounds check in move_map plus binary search This makes move_map faster by skipping all addresses which aren't changing. Also changed the interface from address to offset to avoid computing the offset multiple times. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 1 + src/lisp/ao_lisp_mem.c | 210 ++++++++++++++++++++++++++++--------------------- 2 files changed, 123 insertions(+), 88 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index e238d4fe..af6ff8bb 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -128,6 +128,7 @@ ao_lisp_is_const(ao_poly poly) { #define AO_LISP_IS_CONST(a) (ao_lisp_const <= ((uint8_t *) (a)) && ((uint8_t *) (a)) < ao_lisp_const + AO_LISP_POOL_CONST) #define AO_LISP_IS_POOL(a) (ao_lisp_pool <= ((uint8_t *) (a)) && ((uint8_t *) (a)) < ao_lisp_pool + AO_LISP_POOL) +#define AO_LISP_IS_INT(p) (ao_lisp_base_type(p) == AO_LISP_INT); void * ao_lisp_ref(ao_poly poly); diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 2599f719..e8907cf6 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -236,10 +236,10 @@ static uint8_t ao_lisp_cons_noted; uint16_t ao_lisp_top; struct ao_lisp_chunk { - uint16_t old_addr; + uint16_t old_offset; union { uint16_t size; - uint16_t new_addr; + uint16_t new_offset; }; }; @@ -284,14 +284,11 @@ static inline int limit(int offset) { static int total_marked; static void -note_cons(void *addr) +note_cons(uint16_t offset) { - if (AO_LISP_IS_POOL(addr)) { - int offset = pool_offset(addr); - MDBG_MOVE("note cons %d\n", MDBG_OFFSET(addr)); - ao_lisp_cons_noted = 1; - mark(ao_lisp_cons_note, offset); - } + MDBG_MOVE("note cons %d\n", offset); + ao_lisp_cons_noted = 1; + mark(ao_lisp_cons_note, offset); } static uint16_t chunk_low, chunk_high; @@ -299,11 +296,11 @@ static uint16_t chunk_first, chunk_last; static int chunk_busy; static void -note_chunk(uint16_t addr, uint16_t size) +note_chunk(uint16_t offset, uint16_t size) { int l, r; - if (addr < chunk_low || chunk_high <= addr) + if (offset < chunk_low || chunk_high <= offset) return; /* Binary search for the location */ @@ -311,7 +308,7 @@ note_chunk(uint16_t addr, uint16_t size) r = chunk_busy - 1; while (l <= r) { int m = (l + r) >> 1; - if (ao_lisp_chunk[m].old_addr < addr) + if (ao_lisp_chunk[m].old_offset < offset) l = m + 1; else r = m - 1; @@ -327,7 +324,7 @@ note_chunk(uint16_t addr, uint16_t size) ao_lisp_abort(); /* Off the left side */ - if (l == 0 && chunk_busy && addr > ao_lisp_chunk[0].old_addr) + if (l == 0 && chunk_busy && offset > ao_lisp_chunk[0].old_offset) ao_lisp_abort(); #endif @@ -339,7 +336,7 @@ note_chunk(uint16_t addr, uint16_t size) (end - (l+1)) * sizeof (struct ao_lisp_chunk)); /* Add new entry */ - ao_lisp_chunk[l].old_addr = addr; + ao_lisp_chunk[l].old_offset = offset; ao_lisp_chunk[l].size = size; /* Increment the number of elements up to the size of the array */ @@ -348,7 +345,7 @@ note_chunk(uint16_t addr, uint16_t size) /* Set the top address if the array is full */ if (chunk_busy == AO_LISP_NCHUNK) - chunk_high = ao_lisp_chunk[AO_LISP_NCHUNK-1].old_addr + + chunk_high = ao_lisp_chunk[AO_LISP_NCHUNK-1].old_offset + ao_lisp_chunk[AO_LISP_NCHUNK-1].size; } @@ -508,41 +505,53 @@ ao_lisp_collect(uint8_t style) DUMP_BUSY(); /* Find the first moving object */ - for (i = 0; i < AO_LISP_NCHUNK; i++) { + for (i = 0; i < chunk_busy; i++) { uint16_t size = ao_lisp_chunk[i].size; +#if DBG_MEM if (!size) - break; + ao_lisp_abort(); +#endif - if (ao_lisp_chunk[i].old_addr > top) + if (ao_lisp_chunk[i].old_offset > top) break; + + MDBG_MOVE("chunk %d %d not moving\n", + ao_lisp_chunk[i].old_offset, + ao_lisp_chunk[i].size); #if DBG_MEM - if (ao_lisp_chunk[i].old_addr != top) + if (ao_lisp_chunk[i].old_offset != top) ao_lisp_abort(); #endif - top += size; - MDBG_MOVE("chunk %d %d not moving\n", - ao_lisp_chunk[i].old_addr, - ao_lisp_chunk[i].size); } + /* + * Limit amount of chunk array used in mapping moves + * to the active region + */ chunk_first = i; + chunk_low = ao_lisp_chunk[i].old_offset; + /* Copy all of the objects */ - for (; i < AO_LISP_NCHUNK; i++) { + for (; i < chunk_busy; i++) { uint16_t size = ao_lisp_chunk[i].size; +#if DBG_MEM if (!size) - break; + ao_lisp_abort(); +#endif MDBG_MOVE("chunk %d %d -> %d\n", - ao_lisp_chunk[i].old_addr, + ao_lisp_chunk[i].old_offset, size, top); - ao_lisp_chunk[i].new_addr = top; + ao_lisp_chunk[i].new_offset = top; + memmove(&ao_lisp_pool[top], - &ao_lisp_pool[ao_lisp_chunk[i].old_addr], + &ao_lisp_pool[ao_lisp_chunk[i].old_offset], size); + top += size; } @@ -564,9 +573,13 @@ ao_lisp_collect(uint8_t style) #endif } + /* If we ran into the end of the heap, then + * there's no need to keep walking + */ if (chunk_last != AO_LISP_NCHUNK) break; + /* Next loop starts right above this loop */ chunk_low = chunk_high; } @@ -590,10 +603,11 @@ ao_lisp_collect(uint8_t style) /* * Mark interfaces for objects - * - * Note a reference to memory and - * collect information about a few object sizes - * at a time + */ + +/* + * Note a reference to memory and collect information about a few + * object sizes at a time */ int @@ -614,6 +628,9 @@ ao_lisp_mark_memory(const struct ao_lisp_type *type, void *addr) return 0; } +/* + * Mark an object and all that it refereces + */ int ao_lisp_mark(const struct ao_lisp_type *type, void *addr) { @@ -629,64 +646,82 @@ ao_lisp_mark(const struct ao_lisp_type *type, void *addr) return ret; } +/* + * Mark an object, unless it is a cons cell and + * do_note_cons is set. In that case, just + * set a bit in the cons note array; those + * will be marked in a separate pass to avoid + * deep recursion in the collector + */ int ao_lisp_poly_mark(ao_poly p, uint8_t do_note_cons) { uint8_t type; void *addr; - if (!p) + type = ao_lisp_poly_base_type(p); + + if (type == AO_LISP_INT) return 1; - type = ao_lisp_poly_base_type(p); addr = ao_lisp_ref(p); - if (!AO_LISP_IS_POOL(addr)) return 1; if (type == AO_LISP_CONS && do_note_cons) { - note_cons(ao_lisp_ref(p)); + note_cons(pool_offset(addr)); return 1; } else { - const struct ao_lisp_type *lisp_type; + if (type == AO_LISP_OTHER) + type = ao_lisp_other_type(addr); - if (type == AO_LISP_OTHER) { - type = ao_lisp_other_type(ao_lisp_poly_other(p)); + const struct ao_lisp_type *lisp_type = ao_lisp_types[type]; #if DBG_MEM - if (type <= AO_LISP_OTHER || AO_LISP_NUM_TYPE <= type) - ao_lisp_abort(); + if (!lisp_type) + ao_lisp_abort(); #endif - } - lisp_type = ao_lisp_types[ao_lisp_poly_type(p)]; - if (!lisp_type) - return 1; - return ao_lisp_mark(lisp_type, ao_lisp_ref(p)); + return ao_lisp_mark(lisp_type, addr); } } -static void * -move_map(void *addr) +/* + * Find the current location of an object + * based on the original location. For unmoved + * objects, this is simple. For moved objects, + * go search for it + */ + +static uint16_t +move_map(uint16_t offset) { - uint16_t offset = pool_offset(addr); - int i; - - for (i = chunk_first; i < chunk_last; i++) { - if (ao_lisp_chunk[i].old_addr == offset) { - MDBG_MOVE("move %d -> %d\n", - ao_lisp_chunk[i].old_addr, - ao_lisp_chunk[i].new_addr); - return ao_lisp_pool + ao_lisp_chunk[i].new_addr; - } + int l, r; + + if (offset < chunk_low || chunk_high <= offset) + return offset; + + /* Binary search for the location */ + l = chunk_first; + r = chunk_busy - 1; + while (l <= r) { + int m = (l + r) >> 1; + if (ao_lisp_chunk[m].old_offset < offset) + l = m + 1; + else + r = m - 1; } - return addr; +#if DBG_MEM + if (ao_lisp_chunk[l].old_offset != offset) + ao_lisp_abort(); +#endif + return ao_lisp_chunk[l].new_offset; } int ao_lisp_move_memory(const struct ao_lisp_type *type, void **ref) { void *addr = *ref; - int offset; + uint16_t offset, orig_offset; if (!AO_LISP_IS_POOL(addr)) return 1; @@ -694,14 +729,14 @@ ao_lisp_move_memory(const struct ao_lisp_type *type, void **ref) (void) type; MDBG_MOVE("move memory %d\n", MDBG_OFFSET(addr)); - addr = move_map(addr); - if (addr != *ref) { + orig_offset = pool_offset(addr); + offset = move_map(orig_offset); + if (offset != orig_offset) { MDBG_MOVE("update ref %d %d -> %d\n", AO_LISP_IS_POOL(ref) ? MDBG_OFFSET(ref) : -1, - MDBG_OFFSET(*ref), MDBG_OFFSET(addr)); - *ref = addr; + orig_offset, offset); + *ref = ao_lisp_pool + offset; } - offset = pool_offset(addr); if (busy(ao_lisp_busy, offset)) { MDBG_MOVE("already moved\n"); return 1; @@ -729,47 +764,46 @@ ao_lisp_move(const struct ao_lisp_type *type, void **ref) int ao_lisp_poly_move(ao_poly *ref, uint8_t do_note_cons) { - uint8_t type; - ao_poly p = *ref; - int ret; - void *addr; + uint8_t type; + ao_poly p = *ref; + int ret; + void *addr; + uint16_t offset, orig_offset; + uint8_t base_type; + + base_type = type = ao_lisp_poly_base_type(p); - if (!p) + if (type == AO_LISP_INT) return 1; addr = ao_lisp_ref(p); - if (!AO_LISP_IS_POOL(addr)) return 1; - type = ao_lisp_poly_base_type(p); + orig_offset = pool_offset(addr); + offset = move_map(orig_offset); if (type == AO_LISP_CONS && do_note_cons) { - note_cons(addr); - addr = move_map(addr); + note_cons(orig_offset); ret = 1; } else { - const struct ao_lisp_type *lisp_type; + if (type == AO_LISP_OTHER) + type = ao_lisp_other_type(ao_lisp_pool + offset); - if (type == AO_LISP_OTHER) { - type = ao_lisp_other_type(move_map(ao_lisp_poly_other(p))); + const struct ao_lisp_type *lisp_type = ao_lisp_types[type]; #if DBG_MEM - if (type <= AO_LISP_OTHER || AO_LISP_NUM_TYPE <= type) - ao_lisp_abort(); + if (!lisp_type) + ao_lisp_abort(); #endif - } - lisp_type = ao_lisp_types[type]; - if (!lisp_type) - return 1; ret = ao_lisp_move(lisp_type, &addr); } /* Re-write the poly value */ - if (addr != ao_lisp_ref(p)) { - ao_poly np = ao_lisp_poly(addr, p & AO_LISP_TYPE_MASK); + if (offset != orig_offset) { + ao_poly np = ao_lisp_poly(ao_lisp_pool + offset, base_type); MDBG_MOVE("poly %d moved %d -> %d\n", - type, MDBG_OFFSET(ao_lisp_ref(p)), MDBG_OFFSET(ao_lisp_ref(np))); + type, orig_offset, offset); *ref = np; } return ret; @@ -797,8 +831,8 @@ ao_lisp_alloc(int size) MDBG_DO(if (dbg_validate) ao_lisp_validate()); size = ao_lisp_size_round(size); if (ao_lisp_top + size > AO_LISP_POOL) { - if (!ao_lisp_collect(AO_LISP_COLLECT_INCREMENTAL) && - !ao_lisp_collect(AO_LISP_COLLECT_FULL)) + if (ao_lisp_collect(AO_LISP_COLLECT_INCREMENTAL) < size && + ao_lisp_collect(AO_LISP_COLLECT_FULL) < size) { ao_lisp_error(AO_LISP_OOM, "out of memory"); return NULL; -- cgit v1.2.3 From 8f833f31f625526a5f1e9a1bd561733b5bb2bcaa Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 18 Nov 2016 21:17:54 -0800 Subject: altos/lisp: Build new ao_lisp_stack.c into test and lambdakey Helpful to include the new source file. Signed-off-by: Keith Packard --- src/lambdakey-v1.0/Makefile | 1 + src/test/Makefile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/lambdakey-v1.0/Makefile b/src/lambdakey-v1.0/Makefile index a4d78736..2609bea3 100644 --- a/src/lambdakey-v1.0/Makefile +++ b/src/lambdakey-v1.0/Makefile @@ -50,6 +50,7 @@ ALTOS_SRC = \ ao_lisp_error.c \ ao_lisp_lambda.c \ ao_lisp_save.c \ + ao_lisp_stack.c \ ao_lisp_os_save.c PRODUCT=LambdaKey-v1.0 diff --git a/src/test/Makefile b/src/test/Makefile index 0eaa9421..a22abe46 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -91,7 +91,7 @@ ao_quaternion_test: ao_quaternion_test.c ao_quaternion.h AO_LISP_OBJS = ao_lisp_test.o ao_lisp_mem.o ao_lisp_cons.o ao_lisp_string.o \ ao_lisp_atom.o ao_lisp_int.o ao_lisp_eval.o ao_lisp_poly.o \ ao_lisp_builtin.o ao_lisp_read.o ao_lisp_rep.o ao_lisp_frame.o \ - ao_lisp_lambda.o ao_lisp_error.o ao_lisp_save.o + ao_lisp_lambda.o ao_lisp_error.o ao_lisp_save.o ao_lisp_stack.o ao_lisp_test: $(AO_LISP_OBJS) cc $(CFLAGS) -o $@ $(AO_LISP_OBJS) -- cgit v1.2.3 From c3a4d7721f0f5d082336b8cc9c9d765ad2f7d17e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 18 Nov 2016 22:41:46 -0800 Subject: altos/lisp: Sort frames by atom Fortunately, the collector always retains the relative order between addresses, so we can sort based on the atom address itself. This reduces the time spent looking for names in larger (e.g. global) frames. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 5 ++++- src/lisp/ao_lisp_frame.c | 51 +++++++++++++++++++++++++++++++++++++---------- src/lisp/ao_lisp_lambda.c | 9 +++------ src/lisp/ao_lisp_mem.c | 4 +++- 4 files changed, 50 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index af6ff8bb..1f7c85e1 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -621,7 +621,7 @@ ao_lisp_read_eval_print(void); /* frame */ extern const struct ao_lisp_type ao_lisp_frame_type; -#define AO_LISP_FRAME_FREE 4 +#define AO_LISP_FRAME_FREE 6 extern struct ao_lisp_frame *ao_lisp_frame_free_list[AO_LISP_FRAME_FREE]; @@ -637,6 +637,9 @@ ao_lisp_frame_new(int num); void ao_lisp_frame_free(struct ao_lisp_frame *frame); +void +ao_lisp_frame_bind(struct ao_lisp_frame *frame, int num, ao_poly atom, ao_poly val); + int ao_lisp_frame_add(struct ao_lisp_frame **frame, ao_poly atom, ao_poly val); diff --git a/src/lisp/ao_lisp_frame.c b/src/lisp/ao_lisp_frame.c index 17fa141a..05f6d253 100644 --- a/src/lisp/ao_lisp_frame.c +++ b/src/lisp/ao_lisp_frame.c @@ -128,14 +128,32 @@ ao_lisp_frame_print(ao_poly p) printf("}"); } +static int +ao_lisp_frame_find(struct ao_lisp_frame *frame, int top, ao_poly atom) +{ + int l = 0; + int r = top - 1; + while (l <= r) { + int m = (l + r) >> 1; + if (frame->vals[m].atom < atom) + l = m + 1; + else + r = m - 1; + } + return l; +} + ao_poly * ao_lisp_frame_ref(struct ao_lisp_frame *frame, ao_poly atom) { - int f; - for (f = 0; f < frame->num; f++) - if (frame->vals[f].atom == atom) - return &frame->vals[f].val; - return NULL; + int l = ao_lisp_frame_find(frame, frame->num, atom); + + if (l >= frame->num) + return NULL; + + if (frame->vals[l].atom != atom) + return NULL; + return &frame->vals[l].val; } int @@ -234,6 +252,18 @@ ao_lisp_frame_realloc(struct ao_lisp_frame **frame_ref, int new_num) return new; } +void +ao_lisp_frame_bind(struct ao_lisp_frame *frame, int num, ao_poly atom, ao_poly val) +{ + int l = ao_lisp_frame_find(frame, num, atom); + + memmove(&frame->vals[l+1], + &frame->vals[l], + (num - l) * sizeof (struct ao_lisp_val)); + frame->vals[l].atom = atom; + frame->vals[l].val = val; +} + int ao_lisp_frame_add(struct ao_lisp_frame **frame_ref, ao_poly atom, ao_poly val) { @@ -251,14 +281,13 @@ ao_lisp_frame_add(struct ao_lisp_frame **frame_ref, ao_poly atom, ao_poly val) f = 0; frame = ao_lisp_frame_new(1); } - atom = ao_lisp_poly_fetch(0); - val = ao_lisp_poly_fetch(1); if (!frame) return 0; *frame_ref = frame; - frame->vals[f].atom = atom; - ref = &frame->vals[f].val; - } - *ref = val; + atom = ao_lisp_poly_fetch(0); + val = ao_lisp_poly_fetch(1); + ao_lisp_frame_bind(frame, frame->num - 1, atom, val); + } else + *ref = val; return 1; } diff --git a/src/lisp/ao_lisp_lambda.c b/src/lisp/ao_lisp_lambda.c index b164cd66..526863c5 100644 --- a/src/lisp/ao_lisp_lambda.c +++ b/src/lisp/ao_lisp_lambda.c @@ -166,8 +166,7 @@ ao_lisp_lambda_eval(void) case AO_LISP_FUNC_LAMBDA: for (f = 0; f < args_wanted; f++) { DBGI("bind "); DBG_POLY(args->car); DBG(" = "); DBG_POLY(vals->car); DBG("\n"); - next_frame->vals[f].atom = args->car; - next_frame->vals[f].val = vals->car; + ao_lisp_frame_bind(next_frame, f, args->car, vals->car); args = ao_lisp_poly_cons(args->cdr); vals = ao_lisp_poly_cons(vals->cdr); } @@ -180,14 +179,12 @@ ao_lisp_lambda_eval(void) case AO_LISP_FUNC_MACRO: for (f = 0; f < args_wanted - 1; f++) { DBGI("bind "); DBG_POLY(args->car); DBG(" = "); DBG_POLY(vals->car); DBG("\n"); - next_frame->vals[f].atom = args->car; - next_frame->vals[f].val = vals->car; + ao_lisp_frame_bind(next_frame, f, args->car, vals->car); args = ao_lisp_poly_cons(args->cdr); vals = ao_lisp_poly_cons(vals->cdr); } DBGI("bind "); DBG_POLY(args->car); DBG(" = "); DBG_POLY(ao_lisp_cons_poly(vals)); DBG("\n"); - next_frame->vals[f].atom = args->car; - next_frame->vals[f].val = ao_lisp_cons_poly(vals); + ao_lisp_frame_bind(next_frame, f, args->car, ao_lisp_cons_poly(vals)); break; default: break; diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index e8907cf6..1f09ede8 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -218,9 +218,11 @@ static const void ** const ao_lisp_cache[] = { (const void **) &ao_lisp_frame_free_list[1], (const void **) &ao_lisp_frame_free_list[2], (const void **) &ao_lisp_frame_free_list[3], + (const void **) &ao_lisp_frame_free_list[4], + (const void **) &ao_lisp_frame_free_list[5], }; -#if AO_LISP_FRAME_FREE != 4 +#if AO_LISP_FRAME_FREE != 6 #error Unexpected AO_LISP_FRAME_FREE value #endif -- cgit v1.2.3 From 1b1bc92e6781c563e3d3b117b9cda2dddccc44de Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 18 Nov 2016 22:52:10 -0800 Subject: altos/lisp: Add builtin 'collect' Collect memory, return amount free. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 2 ++ src/lisp/ao_lisp_builtin.c | 11 +++++++++++ src/lisp/ao_lisp_make_const.c | 1 + 3 files changed, 14 insertions(+) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 1f7c85e1..1a8e7e91 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -79,6 +79,7 @@ extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST]; #define _ao_lisp_atom_save _atom("save") #define _ao_lisp_atom_restore _atom("restore") #define _ao_lisp_atom_call2fcc _atom("call/cc") +#define _ao_lisp_atom_collect _atom("collect") #else #include "ao_lisp_const.h" #ifndef AO_LISP_POOL @@ -291,6 +292,7 @@ enum ao_lisp_builtin_id { builtin_save, builtin_restore, builtin_call_cc, + builtin_collect, _builtin_last }; diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index 4c845307..7cd131f5 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -87,6 +87,7 @@ static const ao_poly builtin_names[] = { [builtin_save] = _ao_lisp_atom_save, [builtin_restore] = _ao_lisp_atom_restore, [builtin_call_cc] = _ao_lisp_atom_call2fcc, + [builtin_collect] = _ao_lisp_atom_collect, }; @@ -561,6 +562,15 @@ ao_lisp_do_read(struct ao_lisp_cons *cons) return ao_lisp_read(); } +ao_poly +ao_lisp_do_collect(struct ao_lisp_cons *cons) +{ + int free; + (void) cons; + free = ao_lisp_collect(AO_LISP_COLLECT_FULL); + return ao_lisp_int_poly(free); +} + const ao_lisp_func_t ao_lisp_builtins[] = { [builtin_eval] = ao_lisp_do_eval, [builtin_read] = ao_lisp_do_read, @@ -599,5 +609,6 @@ const ao_lisp_func_t ao_lisp_builtins[] = { [builtin_save] = ao_lisp_save, [builtin_restore] = ao_lisp_restore, [builtin_call_cc] = ao_lisp_call_cc, + [builtin_collect] = ao_lisp_do_collect, }; diff --git a/src/lisp/ao_lisp_make_const.c b/src/lisp/ao_lisp_make_const.c index de9c5725..49f989e6 100644 --- a/src/lisp/ao_lisp_make_const.c +++ b/src/lisp/ao_lisp_make_const.c @@ -72,6 +72,7 @@ struct builtin_func funcs[] = { { .name = "save", .args = AO_LISP_FUNC_F_LAMBDA, .func = builtin_save }, { .name = "restore", .args = AO_LISP_FUNC_F_LAMBDA, .func = builtin_restore }, { .name = "call/cc", .args = AO_LISP_FUNC_F_LAMBDA, .func = builtin_call_cc }, + { .name = "collect", .args = AO_LISP_FUNC_F_LAMBDA, .func = builtin_collect }, }; #define N_FUNC (sizeof funcs / sizeof funcs[0]) -- cgit v1.2.3 From 2c80fea1936ff956df127b43e65139afec3929a0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 18 Nov 2016 22:52:53 -0800 Subject: altos/lisp: Share binary search for memory chunk between mark and move Save some text space. Signed-off-by: Keith Packard --- src/lisp/ao_lisp_mem.c | 109 +++++++++++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 59 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 1f09ede8..5bf6e1e4 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -36,6 +36,10 @@ uint8_t ao_lisp_pool[AO_LISP_POOL + AO_LISP_POOL_EXTRA] __attribute__((aligned(4 #endif +#ifndef DBG_MEM_STATS +#define DBG_MEM_STATS DBG_MEM +#endif + #if DBG_MEM int dbg_move_depth; int dbg_mem = DBG_MEM_START; @@ -283,8 +287,6 @@ static inline int limit(int offset) { return min(AO_LISP_POOL, max(offset, 0)); } -static int total_marked; - static void note_cons(uint16_t offset) { @@ -295,19 +297,14 @@ note_cons(uint16_t offset) static uint16_t chunk_low, chunk_high; static uint16_t chunk_first, chunk_last; -static int chunk_busy; -static void -note_chunk(uint16_t offset, uint16_t size) +static int +find_chunk(uint16_t offset) { int l, r; - - if (offset < chunk_low || chunk_high <= offset) - return; - /* Binary search for the location */ - l = 0; - r = chunk_busy - 1; + l = chunk_first; + r = chunk_last - 1; while (l <= r) { int m = (l + r) >> 1; if (ao_lisp_chunk[m].old_offset < offset) @@ -315,6 +312,19 @@ note_chunk(uint16_t offset, uint16_t size) else r = m - 1; } + return l; +} + +static void +note_chunk(uint16_t offset, uint16_t size) +{ + int l; + + if (offset < chunk_low || chunk_high <= offset) + return; + + l = find_chunk(offset); + /* * The correct location is always in 'l', with r = l-1 being * the entry before the right one @@ -326,12 +336,12 @@ note_chunk(uint16_t offset, uint16_t size) ao_lisp_abort(); /* Off the left side */ - if (l == 0 && chunk_busy && offset > ao_lisp_chunk[0].old_offset) + if (l == 0 && chunk_last && offset > ao_lisp_chunk[0].old_offset) ao_lisp_abort(); #endif /* Shuffle existing entries right */ - int end = min(AO_LISP_NCHUNK, chunk_busy + 1); + int end = min(AO_LISP_NCHUNK, chunk_last + 1); memmove(&ao_lisp_chunk[l+1], &ao_lisp_chunk[l], @@ -342,11 +352,11 @@ note_chunk(uint16_t offset, uint16_t size) ao_lisp_chunk[l].size = size; /* Increment the number of elements up to the size of the array */ - if (chunk_busy < AO_LISP_NCHUNK) - chunk_busy++; + if (chunk_last < AO_LISP_NCHUNK) + chunk_last++; /* Set the top address if the array is full */ - if (chunk_busy == AO_LISP_NCHUNK) + if (chunk_last == AO_LISP_NCHUNK) chunk_high = ao_lisp_chunk[AO_LISP_NCHUNK-1].old_offset + ao_lisp_chunk[AO_LISP_NCHUNK-1].size; } @@ -354,9 +364,9 @@ note_chunk(uint16_t offset, uint16_t size) static void reset_chunks(void) { - memset(ao_lisp_chunk, '\0', sizeof (ao_lisp_chunk)); chunk_high = ao_lisp_top; - chunk_busy = 0; + chunk_last = 0; + chunk_first = 0; } /* @@ -369,7 +379,6 @@ walk(int (*visit_addr)(const struct ao_lisp_type *type, void **addr), { int i; - total_marked = 0; ao_lisp_record_reset(); memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy)); memset(ao_lisp_cons_note, '\0', sizeof (ao_lisp_cons_note)); @@ -452,26 +461,26 @@ ao_lisp_poly_mark_ref(ao_poly *p, uint8_t do_note_cons) return ao_lisp_poly_mark(*p, do_note_cons); } +#if DBG_MEM_STATS int ao_lisp_collects[2]; int ao_lisp_freed[2]; int ao_lisp_loops[2]; +#endif int ao_lisp_last_top; int ao_lisp_collect(uint8_t style) { - int ret; int i; int top; +#if DBG_MEM_STATS int loops = 0; +#endif #if DBG_MEM - int marked; - int moved; struct ao_lisp_record *mark_record = NULL, *move_record = NULL; - MDBG_MOVE("collect %d\n", ao_lisp_collects); - marked = moved = 0; + MDBG_MOVE("collect %d\n", ao_lisp_collects[style]); #endif /* The first time through, we're doing a full collect */ @@ -487,27 +496,25 @@ ao_lisp_collect(uint8_t style) chunk_low = top = ao_lisp_last_top; } for (;;) { +#if DBG_MEM_STATS loops++; +#endif MDBG_MOVE("move chunks from %d to %d\n", chunk_low, top); /* Find the sizes of the first chunk of objects to move */ reset_chunks(); walk(ao_lisp_mark_ref, ao_lisp_poly_mark_ref); #if DBG_MEM - marked = total_marked; ao_lisp_record_free(mark_record); mark_record = ao_lisp_record_save(); if (mark_record && move_record) ao_lisp_record_compare("mark", move_record, mark_record); - - if (moved && moved != marked) - ao_lisp_abort(); #endif DUMP_BUSY(); /* Find the first moving object */ - for (i = 0; i < chunk_busy; i++) { + for (i = 0; i < chunk_last; i++) { uint16_t size = ao_lisp_chunk[i].size; #if DBG_MEM @@ -536,7 +543,7 @@ ao_lisp_collect(uint8_t style) chunk_low = ao_lisp_chunk[i].old_offset; /* Copy all of the objects */ - for (; i < chunk_busy; i++) { + for (; i < chunk_last; i++) { uint16_t size = ao_lisp_chunk[i].size; #if DBG_MEM @@ -557,8 +564,6 @@ ao_lisp_collect(uint8_t style) top += size; } - chunk_last = i; - if (chunk_first < chunk_last) { /* Relocate all references to the objects */ walk(ao_lisp_move, ao_lisp_poly_move); @@ -568,10 +573,6 @@ ao_lisp_collect(uint8_t style) move_record = ao_lisp_record_save(); if (mark_record && move_record) ao_lisp_record_compare("move", mark_record, move_record); - - moved = total_marked; - if (moved != marked) - ao_lisp_abort(); #endif } @@ -585,13 +586,12 @@ ao_lisp_collect(uint8_t style) chunk_low = chunk_high; } - /* Compute amount of memory freed */ - ret = ao_lisp_top - top; - +#if DBG_MEM_STATS /* Collect stats */ ++ao_lisp_collects[style]; - ao_lisp_freed[style] += ret; + ao_lisp_freed[style] += ao_lisp_top - top; ao_lisp_loops[style] += loops; +#endif ao_lisp_top = top; if (style == AO_LISP_COLLECT_FULL) @@ -600,7 +600,7 @@ ao_lisp_collect(uint8_t style) MDBG_DO(memset(ao_lisp_chunk, '\0', sizeof (ao_lisp_chunk)); walk(ao_lisp_mark_ref, ao_lisp_poly_mark_ref)); - return ret; + return AO_LISP_POOL - ao_lisp_top; } /* @@ -697,21 +697,13 @@ ao_lisp_poly_mark(ao_poly p, uint8_t do_note_cons) static uint16_t move_map(uint16_t offset) { - int l, r; + int l; if (offset < chunk_low || chunk_high <= offset) return offset; - /* Binary search for the location */ - l = chunk_first; - r = chunk_busy - 1; - while (l <= r) { - int m = (l + r) >> 1; - if (ao_lisp_chunk[m].old_offset < offset) - l = m + 1; - else - r = m - 1; - } + l = find_chunk(offset); + #if DBG_MEM if (ao_lisp_chunk[l].old_offset != offset) ao_lisp_abort(); @@ -832,13 +824,12 @@ ao_lisp_alloc(int size) MDBG_DO(++dbg_allocs); MDBG_DO(if (dbg_validate) ao_lisp_validate()); size = ao_lisp_size_round(size); - if (ao_lisp_top + size > AO_LISP_POOL) { - if (ao_lisp_collect(AO_LISP_COLLECT_INCREMENTAL) < size && - ao_lisp_collect(AO_LISP_COLLECT_FULL) < size) - { - ao_lisp_error(AO_LISP_OOM, "out of memory"); - return NULL; - } + if (AO_LISP_POOL - ao_lisp_top < size && + ao_lisp_collect(AO_LISP_COLLECT_INCREMENTAL) < size && + ao_lisp_collect(AO_LISP_COLLECT_FULL) < size) + { + ao_lisp_error(AO_LISP_OOM, "out of memory"); + return NULL; } addr = ao_lisp_pool + ao_lisp_top; ao_lisp_top += size; -- cgit v1.2.3 From 129e07ccc9b8a33491a905a91ca6c5b0509aba9c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 18 Nov 2016 22:53:36 -0800 Subject: altos/lisp: Cleanup some DBG defines Get rid of the remaining duplicate defines. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 3 +-- src/lisp/ao_lisp_poly.c | 6 ------ src/lisp/ao_lisp_read.c | 1 - src/lisp/ao_lisp_stack.c | 1 - 4 files changed, 1 insertion(+), 10 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 1a8e7e91..fa3632b1 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -20,7 +20,6 @@ #include #include -//#include #include typedef uint16_t ao_poly; @@ -735,7 +734,7 @@ int ao_lisp_stack_depth; #define DBG_CONS(a) ao_lisp_cons_print(ao_lisp_cons_poly(a)) #define DBG_POLY(a) ao_lisp_poly_print(a) #define OFFSET(a) ((a) ? (int) ((uint8_t *) a - ao_lisp_pool) : -1) -#define DBG_STACK() ao_lisp_stack_print() +#define DBG_STACK() ao_lisp_stack_print(ao_lisp_stack_poly(ao_lisp_stack)) static inline void ao_lisp_frames_dump(void) { diff --git a/src/lisp/ao_lisp_poly.c b/src/lisp/ao_lisp_poly.c index 800ee06d..fb3b06fe 100644 --- a/src/lisp/ao_lisp_poly.c +++ b/src/lisp/ao_lisp_poly.c @@ -14,12 +14,6 @@ #include "ao_lisp.h" -#if 0 -#define DBG(...) printf (__VA_ARGS__) -#else -#define DBG(...) -#endif - struct ao_lisp_funcs { void (*print)(ao_poly); void (*patom)(ao_poly); diff --git a/src/lisp/ao_lisp_read.c b/src/lisp/ao_lisp_read.c index b792c2f1..84ef2a61 100644 --- a/src/lisp/ao_lisp_read.c +++ b/src/lisp/ao_lisp_read.c @@ -12,7 +12,6 @@ * General Public License for more details. */ -#define DBG_EVAL 0 #include "ao_lisp.h" #include "ao_lisp_read.h" diff --git a/src/lisp/ao_lisp_stack.c b/src/lisp/ao_lisp_stack.c index 9c773e83..ef07b88a 100644 --- a/src/lisp/ao_lisp_stack.c +++ b/src/lisp/ao_lisp_stack.c @@ -12,7 +12,6 @@ * General Public License for more details. */ -#define DBG_EVAL 0 #include "ao_lisp.h" const struct ao_lisp_type ao_lisp_stack_type; -- cgit v1.2.3 From 1999b2c915bd5b7df70cffa7777e411d3032d2d5 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 18 Nov 2016 22:57:22 -0800 Subject: altos/lisp: Include memory stats for test program Signed-off-by: Keith Packard --- src/test/ao_lisp_os.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/test/ao_lisp_os.h b/src/test/ao_lisp_os.h index dedcca28..9ff2e1fe 100644 --- a/src/test/ao_lisp_os.h +++ b/src/test/ao_lisp_os.h @@ -24,6 +24,7 @@ #define AO_LISP_POOL_TOTAL 3072 #define AO_LISP_SAVE 1 +#define DBG_MEM_STATS 1 extern int ao_lisp_getc(void); @@ -47,6 +48,8 @@ ao_lisp_os_led(int led) static inline void ao_lisp_os_delay(int delay) { + if (!delay) + return; struct timespec ts = { .tv_sec = delay / 1000, .tv_nsec = (delay % 1000) * 1000000, -- cgit v1.2.3 From 329f76d5e2732ab1c1b10223842d7816275c7e8b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 18 Nov 2016 23:37:44 -0800 Subject: altos/lisp: Move stack recursion check after null check Don't crash when printing null stack this way. Signed-off-by: Keith Packard --- src/lisp/ao_lisp_stack.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp_stack.c b/src/lisp/ao_lisp_stack.c index ef07b88a..53adf432 100644 --- a/src/lisp/ao_lisp_stack.c +++ b/src/lisp/ao_lisp_stack.c @@ -160,11 +160,11 @@ ao_lisp_stack_print(ao_poly poly) { struct ao_lisp_stack *s = ao_lisp_poly_stack(poly); - if (s->type & AO_LISP_STACK_PRINT) { - printf("[recurse...]"); - return; - } while (s) { + if (s->type & AO_LISP_STACK_PRINT) { + printf("[recurse...]"); + return; + } s->type |= AO_LISP_STACK_PRINT; printf("\t[\n"); printf("\t\texpr: "); ao_lisp_poly_print(s->list); printf("\n"); -- cgit v1.2.3 From 30d6b241447cb922b9316e86817f6e31eb973eed Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 20 Nov 2016 01:41:59 -0800 Subject: altos/lisp: Clean up hanoi.lisp demo a bit No serious changes. Signed-off-by: Keith Packard --- src/test/hanoi.lisp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/test/hanoi.lisp b/src/test/hanoi.lisp index b5f2d0f5..e2eb0fa0 100644 --- a/src/test/hanoi.lisp +++ b/src/test/hanoi.lisp @@ -17,11 +17,11 @@ ; ANSI control sequences (defun move-to (col row) - (patom "\033[" row ";" col "H" nil) + (patom "\033[" row ";" col "H") ) (defun clear () - (patom "\033[2J" nil) + (patom "\033[2J") ) (defun display-string (x y str) @@ -112,6 +112,8 @@ ; Move a piece from the top of one stack ; to the top of another +(setq move-delay 100) + (defun move-piece (from to) (let ((from-stack (nth stacks from)) (to-stack (nth stacks to)) @@ -121,7 +123,7 @@ (setq stacks (replace stacks from from-stack)) (setq stacks (replace stacks to to-stack)) (display) - (delay 100) + (delay move-delay) ) ) @@ -149,4 +151,5 @@ (clear) (_hanoi len 0 1 2) (move-to 0 23) + t ) -- cgit v1.2.3 From 399ba0a62422f71ff9669ba03b6a058bb2981c27 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 10 Jan 2017 14:45:59 -0800 Subject: altos/lisp: Tell compiler that the two lisp memory pools are aligned Otherwise, it will generate unaligned accesses to things fetched from them. Sigh. Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index fa3632b1..8f5c3d8e 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -50,7 +50,7 @@ ao_lisp_os_restore(void); #ifdef AO_LISP_MAKE_CONST #define AO_LISP_POOL_CONST 16384 -extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST]; +extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4))); #define ao_lisp_pool ao_lisp_const #define AO_LISP_POOL AO_LISP_POOL_CONST @@ -84,7 +84,7 @@ extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST]; #ifndef AO_LISP_POOL #define AO_LISP_POOL 3072 #endif -extern uint8_t ao_lisp_pool[AO_LISP_POOL + AO_LISP_POOL_EXTRA]; +extern uint8_t ao_lisp_pool[AO_LISP_POOL + AO_LISP_POOL_EXTRA] __attribute__((aligned(4))); #endif /* Primitive types */ -- cgit v1.2.3 From 9c85c9d60334edc2af65a47124873e94e0ff1e9c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 10 Jan 2017 14:47:03 -0800 Subject: altos/lisp: Add casts to keep the latest GCC from whinging Something about alignment issues. Signed-off-by: Keith Packard --- src/lisp/ao_lisp_mem.c | 8 ++++---- src/lisp/ao_lisp_save.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/lisp/ao_lisp_mem.c b/src/lisp/ao_lisp_mem.c index 5bf6e1e4..d067ea07 100644 --- a/src/lisp/ao_lisp_mem.c +++ b/src/lisp/ao_lisp_mem.c @@ -169,15 +169,15 @@ static const struct ao_lisp_root ao_lisp_root[] = { }, { .type = NULL, - .addr = (void **) &save_poly[0] + .addr = (void **) (void *) &save_poly[0] }, { .type = NULL, - .addr = (void **) &save_poly[1] + .addr = (void **) (void *) &save_poly[1] }, { .type = NULL, - .addr = (void **) &save_poly[2] + .addr = (void **) (void *) &save_poly[2] }, { .type = &ao_lisp_atom_type, @@ -197,7 +197,7 @@ static const struct ao_lisp_root ao_lisp_root[] = { }, { .type = NULL, - .addr = (void **) &ao_lisp_v, + .addr = (void **) (void *) &ao_lisp_v, }, { .type = &ao_lisp_cons_type, diff --git a/src/lisp/ao_lisp_save.c b/src/lisp/ao_lisp_save.c index e6e8b65e..4f850fb9 100644 --- a/src/lisp/ao_lisp_save.c +++ b/src/lisp/ao_lisp_save.c @@ -21,7 +21,7 @@ ao_lisp_save(struct ao_lisp_cons *cons) return AO_LISP_NIL; #ifdef AO_LISP_SAVE - struct ao_lisp_os_save *os = (struct ao_lisp_os_save *) &ao_lisp_pool[AO_LISP_POOL]; + struct ao_lisp_os_save *os = (struct ao_lisp_os_save *) (void *) &ao_lisp_pool[AO_LISP_POOL]; ao_lisp_collect(AO_LISP_COLLECT_FULL); os->atoms = ao_lisp_atom_poly(ao_lisp_atoms); @@ -43,7 +43,7 @@ ao_lisp_restore(struct ao_lisp_cons *cons) #ifdef AO_LISP_SAVE struct ao_lisp_os_save save; - struct ao_lisp_os_save *os = (struct ao_lisp_os_save *) &ao_lisp_pool[AO_LISP_POOL]; + struct ao_lisp_os_save *os = (struct ao_lisp_os_save *) (void *) &ao_lisp_pool[AO_LISP_POOL]; if (!ao_lisp_os_restore_save(&save, AO_LISP_POOL)) return ao_lisp_error(AO_LISP_INVALID, "header restore failed"); -- cgit v1.2.3 From bc076747f6cc00508aef909a3a5bd3edf8c9bd66 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 18 Feb 2017 12:14:59 -0800 Subject: altos/lisp: Start adding scheme symbols Migrating to something more like scheme Signed-off-by: Keith Packard --- src/lisp/ao_lisp.h | 4 ++++ src/lisp/ao_lisp_builtin.c | 4 ++++ 2 files changed, 8 insertions(+) (limited to 'src') diff --git a/src/lisp/ao_lisp.h b/src/lisp/ao_lisp.h index 8f5c3d8e..980514cc 100644 --- a/src/lisp/ao_lisp.h +++ b/src/lisp/ao_lisp.h @@ -79,6 +79,10 @@ extern uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4))); #define _ao_lisp_atom_restore _atom("restore") #define _ao_lisp_atom_call2fcc _atom("call/cc") #define _ao_lisp_atom_collect _atom("collect") +#define _ao_lisp_atom_symbolp _atom("symbol?") +#define _ao_lisp_atom_builtin _atom("builtin?") +#define _ao_lisp_atom_symbolp _atom("symbol?") +#define _ao_lisp_atom_symbolp _atom("symbol?") #else #include "ao_lisp_const.h" #ifndef AO_LISP_POOL diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index 7cd131f5..006c32f9 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -88,6 +88,10 @@ static const ao_poly builtin_names[] = { [builtin_restore] = _ao_lisp_atom_restore, [builtin_call_cc] = _ao_lisp_atom_call2fcc, [builtin_collect] = _ao_lisp_atom_collect, + [builtin_symbolp] = _ao_lisp_atom_symbolp, + [builtin_listp] = _ao_lisp_atom_listp, + [builtin_stringp] = _ao_lisp_atom_stringp, + [builtin_numberp] = _ao_lisp_atom_numberp, }; -- cgit v1.2.3 From d96224c2fdc535d08de23aec30d62d4ada9fb8d3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 22 Jan 2017 15:29:13 -0800 Subject: altos/chaoskey: use both halves of the CRC When pulling 16 bits from the 32-bit crc, instead of just using the low bits, xor the two halves together. This appears to even out the number of zero and one bits. Signed-off-by: Keith Packard --- src/chaoskey-v1.0/Makefile | 1 + src/stmf0/ao_crc.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/chaoskey-v1.0/Makefile b/src/chaoskey-v1.0/Makefile index f6b78d07..f2c168ba 100644 --- a/src/chaoskey-v1.0/Makefile +++ b/src/chaoskey-v1.0/Makefile @@ -14,6 +14,7 @@ INC = \ ao_task.h \ ao_adc_fast.h \ ao_power.h \ + ao_crc.h \ stm32f0.h # diff --git a/src/stmf0/ao_crc.h b/src/stmf0/ao_crc.h index 7acc6f9c..b6d91023 100644 --- a/src/stmf0/ao_crc.h +++ b/src/stmf0/ao_crc.h @@ -35,7 +35,8 @@ static inline uint16_t ao_crc_in_32_out_16(uint32_t v) { stm_crc.dr.u32 = v; - return stm_crc.dr.u16; + v = stm_crc.dr.u32; + return v ^ (v >> 16); } static inline uint16_t -- cgit v1.2.3 From 51edc29f5ba758ef8ba4fdd5f53fdabc6a31c98a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 28 Jan 2017 15:33:53 -0800 Subject: altos: Eliminate printf format warning with long vs int Signed-off-by: Keith Packard --- src/kernel/ao_cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/kernel/ao_cmd.c b/src/kernel/ao_cmd.c index 077d7de1..881f3500 100644 --- a/src/kernel/ao_cmd.c +++ b/src/kernel/ao_cmd.c @@ -310,7 +310,7 @@ version(void) #endif #endif #if defined(AO_BOOT_APPLICATION_BASE) && defined(AO_BOOT_APPLICATION_BOUND) - , (uint32_t) AO_BOOT_APPLICATION_BOUND - (uint32_t) AO_BOOT_APPLICATION_BASE + , (unsigned) ((uint32_t) AO_BOOT_APPLICATION_BOUND - (uint32_t) AO_BOOT_APPLICATION_BASE) #endif ); printf("software-version %s\n", ao_version); -- cgit v1.2.3 From f85997eb53779e637dca697d0d96da7d1235fa80 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 3 Feb 2017 06:51:11 +0100 Subject: altos/stmf0: Allow apps to leave interrupt vectors at 0 TeleMini v3.0 doesn't need a boot loader, so we'll have the app run its interrupt vector right at the bottom of the address space instead of copying it to the bottom of ram and reconfiguring the chip to use that. Signed-off-by: Keith Packard --- src/stmf0/ao_interrupt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/stmf0/ao_interrupt.c b/src/stmf0/ao_interrupt.c index 79412483..fcd330f1 100644 --- a/src/stmf0/ao_interrupt.c +++ b/src/stmf0/ao_interrupt.c @@ -26,9 +26,11 @@ #define IS_FLASH_LOADER 0 #endif +#ifndef RELOCATE_INTERRUPT #if !IS_FLASH_LOADER #define RELOCATE_INTERRUPT 1 #endif +#endif extern void main(void); extern char __stack__; -- cgit v1.2.3 From 3770a5f527cb6d519ce22fe91e0cc4078bf72661 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 18 Feb 2017 22:53:03 -0800 Subject: altos/stmf0: Complain if the SPI configuration isn't complete If the pin usage values SPI_1_PA5_PA6_PA7 or SPI_1_PB3_PB4_PB5 aren't defined, then the speed values for the pins aren't going to get set correctly, which results in erratic SPI behaviour. Signed-off-by: Keith Packard --- src/stmf0/ao_spi_stm.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/stmf0/ao_spi_stm.c b/src/stmf0/ao_spi_stm.c index 0448ad8c..5e76d6c3 100644 --- a/src/stmf0/ao_spi_stm.c +++ b/src/stmf0/ao_spi_stm.c @@ -536,12 +536,18 @@ void ao_spi_init(void) { #if HAS_SPI_1 +#ifndef SPI_1_PA5_PA6_PA7 +#error SPI_1_PA5_PA6_PA7 undefined +#endif # if SPI_1_PA5_PA6_PA7 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN); stm_ospeedr_set(&stm_gpioa, 5, SPI_1_OSPEEDR); stm_ospeedr_set(&stm_gpioa, 6, SPI_1_OSPEEDR); stm_ospeedr_set(&stm_gpioa, 7, SPI_1_OSPEEDR); # endif +# ifndef SPI_1_PB3_PB4_PB5 +# error SPI_1_PB3_PB4_PB5 undefined +# endif # if SPI_1_PB3_PB4_PB5 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN); stm_ospeedr_set(&stm_gpiob, 3, SPI_1_OSPEEDR); -- cgit v1.2.3 From cf10239e5485a101fcd7a12b28be927af94d577a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 18 Feb 2017 22:54:35 -0800 Subject: altos/stmf0: Allow projects to not use the USB boot loader Let applications define HAS_BOOT_LOADER on their own if desired. Signed-off-by: Keith Packard --- src/stmf0/ao_arch.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/stmf0/ao_arch.h b/src/stmf0/ao_arch.h index a36482b6..c5f451f5 100644 --- a/src/stmf0/ao_arch.h +++ b/src/stmf0/ao_arch.h @@ -144,10 +144,15 @@ ao_adc_init(); /* ADC maximum reported value */ #define AO_ADC_MAX 4095 +#ifndef HAS_BOOT_LOADER +#define HAS_BOOT_LOADER 1 +#endif + +#if HAS_BOOT_LOADER #define AO_BOOT_APPLICATION_BASE ((uint32_t *) 0x08001000) #define AO_BOOT_APPLICATION_BOUND ((uint32_t *) (0x08000000 + stm_flash_size())) #define AO_BOOT_LOADER_BASE ((uint32_t *) 0x08000000) -#define HAS_BOOT_LOADER 1 +#endif #endif /* _AO_ARCH_H_ */ -- cgit v1.2.3 From 0bf267a6e2d401c8bd6a06d995e3d000777d622a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 18 Feb 2017 22:55:41 -0800 Subject: altos: Allow applications to define LEDs for ao_report.c In case they don't have both a red and green LED. Signed-off-by: Keith Packard --- src/kernel/ao_report.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/kernel/ao_report.c b/src/kernel/ao_report.c index 6592d616..af48b390 100644 --- a/src/kernel/ao_report.c +++ b/src/kernel/ao_report.c @@ -45,9 +45,16 @@ static const uint8_t flight_reports[] = { #define mid(time) ao_beep_for(AO_BEEP_MID, time) #define high(time) ao_beep_for(AO_BEEP_HIGH, time) #else -#define low(time) ao_led_for(AO_LED_GREEN, time) -#define mid(time) ao_led_for(AO_LED_RED, time) -#define high(time) ao_led_for(AO_LED_GREEN|AO_LED_RED, time) +#ifndef AO_LED_LOW +#define AO_LED_LOW AO_LED_GREEN +#endif +#ifndef AO_LED_MID +#define AO_LED_MID AO_LED_RED +#endif + +#define low(time) ao_led_for(AO_LED_LOW, time) +#define mid(time) ao_led_for(AO_LED_MID, time) +#define high(time) ao_led_for(AO_LED_MID|AO_LED_LOW, time) #endif #define pause(time) ao_delay(time) -- cgit v1.2.3 From 1dc31a46f1d1adfdeab444664e581a780d995bf7 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 18 Feb 2017 22:49:34 -0800 Subject: altos: Require SPI speed to be declared for cc1200 The cc1200 can't run SPI faster than 10MHz, so make sure every device picks a SPI clock slower than that. Signed-off-by: Keith Packard --- src/drivers/ao_cc1200.c | 8 ++++++-- src/telebt-v3.0/ao_pins.h | 1 + src/teledongle-v3.0/ao_pins.h | 1 + src/telefiretwo-v0.1/ao_pins.h | 1 + src/telelco-v0.3/ao_pins.h | 1 + src/telelcotwo-v0.1/ao_pins.h | 1 + src/telemega-v2.0/ao_pins.h | 1 + src/telemetrum-v3.0/ao_pins.h | 1 + 8 files changed, 13 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_cc1200.c b/src/drivers/ao_cc1200.c index 2bc99734..de282000 100644 --- a/src/drivers/ao_cc1200.c +++ b/src/drivers/ao_cc1200.c @@ -51,7 +51,11 @@ extern const uint32_t ao_radio_cal; #define FOSC 40000000 #endif -#define ao_radio_select() ao_spi_get_mask(AO_CC1200_SPI_CS_PORT,(1 << AO_CC1200_SPI_CS_PIN),AO_CC1200_SPI_BUS,AO_SPI_SPEED_FAST) +#ifndef AO_CC1200_SPI_SPEED +#error AO_CC1200_SPI_SPEED undefined +#endif + +#define ao_radio_select() ao_spi_get_mask(AO_CC1200_SPI_CS_PORT,(1 << AO_CC1200_SPI_CS_PIN),AO_CC1200_SPI_BUS,AO_CC1200_SPI_SPEED) #define ao_radio_deselect() ao_spi_put_mask(AO_CC1200_SPI_CS_PORT,(1 << AO_CC1200_SPI_CS_PIN),AO_CC1200_SPI_BUS) #define ao_radio_spi_send(d,l) ao_spi_send((d), (l), AO_CC1200_SPI_BUS) #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC1200_SPI_BUS) @@ -1323,7 +1327,7 @@ static void ao_radio_packet(void) { void ao_radio_test_recv(void) { - uint8_t bytes[34]; + static uint8_t bytes[34]; uint8_t b; if (ao_radio_recv(bytes, 34, 0)) { diff --git a/src/telebt-v3.0/ao_pins.h b/src/telebt-v3.0/ao_pins.h index 61cbe9bb..1f7af41b 100644 --- a/src/telebt-v3.0/ao_pins.h +++ b/src/telebt-v3.0/ao_pins.h @@ -197,6 +197,7 @@ struct ao_adc { #define AO_CC1200_SPI_CS_PIN 10 #define AO_CC1200_SPI_BUS AO_SPI_1_PA5_PA6_PA7 #define AO_CC1200_SPI stm_spi1 +#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST #define AO_CC1200_INT_PORT (&stm_gpiob) #define AO_CC1200_INT_PIN (11) diff --git a/src/teledongle-v3.0/ao_pins.h b/src/teledongle-v3.0/ao_pins.h index effc2322..be710aef 100644 --- a/src/teledongle-v3.0/ao_pins.h +++ b/src/teledongle-v3.0/ao_pins.h @@ -96,6 +96,7 @@ #define AO_CC1200_SPI_CS_PIN 3 #define AO_CC1200_SPI_BUS 0 #define AO_CC1200_SPI 0 +#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_8MHz #define AO_CC1200_INT_PORT 0 #define AO_CC1200_INT_PIN 2 diff --git a/src/telefiretwo-v0.1/ao_pins.h b/src/telefiretwo-v0.1/ao_pins.h index f56061b2..1e5c0d09 100644 --- a/src/telefiretwo-v0.1/ao_pins.h +++ b/src/telefiretwo-v0.1/ao_pins.h @@ -110,6 +110,7 @@ #define AO_CC1200_SPI_CS_PIN 7 #define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15 #define AO_CC1200_SPI stm_spi2 +#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST #define AO_CC1200_INT_PORT (&stm_gpiob) #define AO_CC1200_INT_PIN (11) diff --git a/src/telelco-v0.3/ao_pins.h b/src/telelco-v0.3/ao_pins.h index d874a19b..dd4aaafb 100644 --- a/src/telelco-v0.3/ao_pins.h +++ b/src/telelco-v0.3/ao_pins.h @@ -89,6 +89,7 @@ #define AO_CC1200_SPI_CS_PIN 0 #define AO_CC1200_SPI_BUS AO_SPI_2_PD1_PD3_PD4 #define AO_CC1200_SPI stm_spi2 +#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST #define AO_CC1200_INT_PORT (&stm_gpioc) #define AO_CC1200_INT_PIN (15) diff --git a/src/telelcotwo-v0.1/ao_pins.h b/src/telelcotwo-v0.1/ao_pins.h index 714a5c3a..60e94c67 100644 --- a/src/telelcotwo-v0.1/ao_pins.h +++ b/src/telelcotwo-v0.1/ao_pins.h @@ -91,6 +91,7 @@ #define AO_CC1200_SPI_CS_PIN 7 #define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15 #define AO_CC1200_SPI stm_spi2 +#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST #define AO_CC1200_INT_PORT (&stm_gpiob) #define AO_CC1200_INT_PIN (11) diff --git a/src/telemega-v2.0/ao_pins.h b/src/telemega-v2.0/ao_pins.h index b1c472da..c7c8ad19 100644 --- a/src/telemega-v2.0/ao_pins.h +++ b/src/telemega-v2.0/ao_pins.h @@ -309,6 +309,7 @@ struct ao_adc { #define AO_CC1200_SPI_CS_PIN 5 #define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15 #define AO_CC1200_SPI stm_spi2 +#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST #define AO_CC1200_INT_PORT (&stm_gpioe) #define AO_CC1200_INT_PIN 1 diff --git a/src/telemetrum-v3.0/ao_pins.h b/src/telemetrum-v3.0/ao_pins.h index ccf2f18f..b937b422 100644 --- a/src/telemetrum-v3.0/ao_pins.h +++ b/src/telemetrum-v3.0/ao_pins.h @@ -259,6 +259,7 @@ struct ao_adc { #define AO_CC1200_SPI_CS_PIN 2 #define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15 #define AO_CC1200_SPI stm_spi2 +#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST #define AO_CC1200_INT_PORT (&stm_gpioa) #define AO_CC1200_INT_PIN (3) -- cgit v1.2.3 From b94fe9915b33283df6b86bcdc96ceada1fc71ce6 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 19 Feb 2017 17:42:05 -0800 Subject: altos/stmf0: Add adc and beep support for TeleMini v3.0 Note that the ADC code is running very slowly as required by the high impedance dividers on the TeleMini v3.0 pyro circuits. Signed-off-by: Keith Packard --- src/stmf0/altos-raw.ld | 85 +++++++++++ src/stmf0/ao_adc_stm.c | 340 +++++++++++++++++++++++++++++++++++++++++++ src/stmf0/ao_beep_stm.c | 185 +++++++++++++++++++++++ src/stmf0/ao_spi_stm_slave.c | 339 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 949 insertions(+) create mode 100644 src/stmf0/altos-raw.ld create mode 100644 src/stmf0/ao_adc_stm.c create mode 100644 src/stmf0/ao_beep_stm.c create mode 100644 src/stmf0/ao_spi_stm_slave.c (limited to 'src') diff --git a/src/stmf0/altos-raw.ld b/src/stmf0/altos-raw.ld new file mode 100644 index 00000000..eb285e07 --- /dev/null +++ b/src/stmf0/altos-raw.ld @@ -0,0 +1,85 @@ +/* + * Copyright © 2012 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +MEMORY { + rom (rx) : ORIGIN = 0x08000000, LENGTH = 32K + ram (!w) : ORIGIN = 0x20000000, LENGTH = 6k - 128 + stack (!w) : ORIGIN = 0x20000000 + 6k - 128, LENGTH = 128 +} + +INCLUDE registers.ld + +EXTERN (stm_interrupt_vector) + +SECTIONS { + /* + * Rom contents + */ + + .interrupt : { + __text_start__ = .; + *(.interrupt) /* Interrupt vectors */ + } > rom + + .text ORIGIN(rom) + 0x100 : { + + /* Ick. What I want is to specify the + * addresses of some global constants so + * that I can find them across versions + * of the application. I can't figure out + * how to make gnu ld do that, so instead + * we just load the two files that include + * these defines in the right order here and + * expect things to 'just work'. Don't change + * the contents of those files, ok? + */ + ao_romconfig.o(.romconfig*) + ao_product.o(.romconfig*) + + *(.text*) /* Executable code */ + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.rodata*) /* Constants */ + + } > rom + __text_end__ = .; + + /* Data -- relocated to RAM, but written to ROM + */ + .data : { + __data_start__ = .; + *(.data) /* initialized data */ + . = ALIGN(4); + __data_end__ = .; + } >ram AT>rom + + .bss : { + __bss_start__ = .; + *(.bss) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } >ram + + PROVIDE(end = .); + + PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack)); +} + +ENTRY(start); + + diff --git a/src/stmf0/ao_adc_stm.c b/src/stmf0/ao_adc_stm.c new file mode 100644 index 00000000..2b23dc50 --- /dev/null +++ b/src/stmf0/ao_adc_stm.c @@ -0,0 +1,340 @@ +/* + * Copyright © 2015 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include + +#define AO_ADC_DEBUG 0 + +static uint8_t ao_adc_ready; + +/* + * Callback from DMA ISR + * + * Mark time in ring, shut down DMA engine + */ +static void ao_adc_done(int index) +{ + (void) index; + /* Clear ISR bits */ + stm_adc.isr = ((1 << STM_ADC_ISR_AWD) | + (1 << STM_ADC_ISR_OVR) | + (1 << STM_ADC_ISR_EOSEQ) | + (1 << STM_ADC_ISR_EOC)); + + AO_DATA_PRESENT(AO_DATA_ADC); + ao_dma_done_transfer(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1)); + if (ao_data_present == AO_DATA_ALL) { +#if HAS_MS5607 + ao_data_ring[ao_data_head].ms5607_raw = ao_ms5607_current; +#endif +#if HAS_MMA655X + ao_data_ring[ao_data_head].mma655x = ao_mma655x_current; +#endif +#if HAS_HMC5883 + ao_data_ring[ao_data_head].hmc5883 = ao_hmc5883_current; +#endif +#if HAS_MPU6000 + ao_data_ring[ao_data_head].mpu6000 = ao_mpu6000_current; +#endif + ao_data_ring[ao_data_head].tick = ao_tick_count; + ao_data_head = ao_data_ring_next(ao_data_head); + ao_wakeup((void *) &ao_data_head); + } + ao_adc_ready = 1; +} + +/* + * Start the ADC sequence using the DMA engine + */ +void +ao_adc_poll(void) +{ + if (!ao_adc_ready) + return; + ao_adc_ready = 0; + stm_adc.isr = 0; + ao_dma_set_transfer(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1), + &stm_adc.dr, + (void *) (&ao_data_ring[ao_data_head].adc), + AO_NUM_ADC, + (0 << STM_DMA_CCR_MEM2MEM) | + (STM_DMA_CCR_PL_HIGH << STM_DMA_CCR_PL) | + (STM_DMA_CCR_MSIZE_16 << STM_DMA_CCR_MSIZE) | + (STM_DMA_CCR_PSIZE_16 << STM_DMA_CCR_PSIZE) | + (1 << STM_DMA_CCR_MINC) | + (0 << STM_DMA_CCR_PINC) | + (0 << STM_DMA_CCR_CIRC) | + (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) | + (1 << STM_DMA_CCR_TCIE)); + ao_dma_set_isr(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1), ao_adc_done); + ao_dma_start(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1)); + + stm_adc.cr |= (1 << STM_ADC_CR_ADSTART); +} + +static void +ao_adc_dump(void) +{ + struct ao_data packet; + + ao_data_get(&packet); + AO_ADC_DUMP(&packet); +} + +#if AO_ADC_DEBUG +static void +ao_adc_one(void) +{ + int ch; + uint16_t value; + + ao_cmd_decimal(); + if (ao_cmd_status != ao_cmd_success) + return; + ch = ao_cmd_lex_i; + if (ch < 0 || AO_NUM_ADC <= ch) { + ao_cmd_status = ao_cmd_syntax_error; + return; + } + + ao_timer_set_adc_interval(0); + ao_delay(1); + + printf("At top, data %u isr %04x cr %04x\n", stm_adc.dr, stm_adc.isr, stm_adc.cr); + + if (stm_adc.cr & (1 << STM_ADC_CR_ADEN)) { + printf("Disabling\n"); flush(); + stm_adc.cr |= (1 << STM_ADC_CR_ADDIS); + while (stm_adc.cr & (1 << STM_ADC_CR_ADDIS)) + ; + printf("Disabled\n"); flush(); + } + + /* Turn off everything */ + stm_adc.cr &= ~((1 << STM_ADC_CR_ADCAL) | + (1 << STM_ADC_CR_ADSTP) | + (1 << STM_ADC_CR_ADSTART) | + (1 << STM_ADC_CR_ADEN)); + + printf("After disable, ADC status %04x\n", stm_adc.cr); + + /* Configure */ + stm_adc.cfgr1 = ((0 << STM_ADC_CFGR1_AWDCH) | /* analog watchdog channel 0 */ + (0 << STM_ADC_CFGR1_AWDEN) | /* Disable analog watchdog */ + (0 << STM_ADC_CFGR1_AWDSGL) | /* analog watchdog on all channels */ + (0 << STM_ADC_CFGR1_DISCEN) | /* Not discontinuous mode. All channels converted with one trigger */ + (0 << STM_ADC_CFGR1_AUTOOFF) | /* Leave ADC running */ + (1 << STM_ADC_CFGR1_WAIT) | /* Wait for data to be read before next conversion */ + (0 << STM_ADC_CFGR1_CONT) | /* only one set of conversions per trigger */ + (1 << STM_ADC_CFGR1_OVRMOD) | /* overwrite on overrun */ + (STM_ADC_CFGR1_EXTEN_DISABLE << STM_ADC_CFGR1_EXTEN) | /* SW trigger */ + (0 << STM_ADC_CFGR1_ALIGN) | /* Align to LSB */ + (STM_ADC_CFGR1_RES_12 << STM_ADC_CFGR1_RES) | /* 12 bit resolution */ + (STM_ADC_CFGR1_SCANDIR_UP << STM_ADC_CFGR1_SCANDIR) | /* scan 0 .. n */ + (STM_ADC_CFGR1_DMACFG_ONESHOT << STM_ADC_CFGR1_DMACFG) | /* one set of conversions then stop */ + (0 << STM_ADC_CFGR1_DMAEN)); /* disable DMA */ + + stm_adc.chselr = (1 << ch); + + /* Longest sample time */ + stm_adc.smpr = STM_ADC_SMPR_SMP_41_5 << STM_ADC_SMPR_SMP; + + printf("Before enable, ADC status %04x\n", stm_adc.cr); flush(); + /* Enable */ + stm_adc.cr |= (1 << STM_ADC_CR_ADEN); + while ((stm_adc.isr & (1 << STM_ADC_ISR_ADRDY)) == 0) + ; + + /* Start */ + stm_adc.cr |= (1 << STM_ADC_CR_ADSTART); + + /* Wait for conversion complete */ + while (!(stm_adc.isr & (1 << STM_ADC_ISR_EOC))) + ; + + value = stm_adc.dr; + printf ("value %u, cr is %04x isr is %04x\n", + value, stm_adc.cr, stm_adc.isr); + + + /* Clear ISR bits */ + stm_adc.isr = ((1 << STM_ADC_ISR_AWD) | + (1 << STM_ADC_ISR_OVR) | + (1 << STM_ADC_ISR_EOSEQ) | + (1 << STM_ADC_ISR_EOC)); +} +#endif + +__code struct ao_cmds ao_adc_cmds[] = { + { ao_adc_dump, "a\0Display current ADC values" }, +#if AO_ADC_DEBUG + { ao_adc_one, "A ch\0Display one ADC channel" }, +#endif + { 0, NULL }, +}; + +void +ao_adc_init(void) +{ + uint32_t chselr; + + /* Reset ADC */ + stm_rcc.apb2rstr |= (1 << STM_RCC_APB2RSTR_ADCRST); + stm_rcc.apb2rstr &= ~(1 << STM_RCC_APB2RSTR_ADCRST); + + /* Turn on ADC pins */ + stm_rcc.ahbenr |= AO_ADC_RCC_AHBENR; + +#ifdef AO_ADC_PIN0_PORT + stm_moder_set(AO_ADC_PIN0_PORT, AO_ADC_PIN0_PIN, STM_MODER_ANALOG); + stm_pupdr_set(AO_ADC_PIN0_PORT, AO_ADC_PIN0_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN1_PORT + stm_moder_set(AO_ADC_PIN1_PORT, AO_ADC_PIN1_PIN, STM_MODER_ANALOG); + stm_pupdr_set(AO_ADC_PIN1_PORT, AO_ADC_PIN1_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN2_PORT + stm_moder_set(AO_ADC_PIN2_PORT, AO_ADC_PIN2_PIN, STM_MODER_ANALOG); + stm_pupdr_set(AO_ADC_PIN2_PORT, AO_ADC_PIN2_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN3_PORT + stm_moder_set(AO_ADC_PIN3_PORT, AO_ADC_PIN3_PIN, STM_MODER_ANALOG); + stm_pupdr_set(AO_ADC_PIN3_PORT, AO_ADC_PIN3_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN4_PORT + stm_moder_set(AO_ADC_PIN4_PORT, AO_ADC_PIN4_PIN, STM_MODER_ANALOG); + stm_pupdr_set(AO_ADC_PIN4_PORT, AO_ADC_PIN4_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN5_PORT + stm_moder_set(AO_ADC_PIN5_PORT, AO_ADC_PIN5_PIN, STM_MODER_ANALOG); + stm_pupdr_set(AO_ADC_PIN5_PORT, AO_ADC_PIN5_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN6_PORT + stm_moder_set(AO_ADC_PIN6_PORT, AO_ADC_PIN6_PIN, STM_MODER_ANALOG); + stm_pupdr_set(AO_ADC_PIN6_PORT, AO_ADC_PIN6_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN7_PORT + stm_moder_set(AO_ADC_PIN7_PORT, AO_ADC_PIN7_PIN, STM_MODER_ANALOG); + stm_pupdr_set(AO_ADC_PIN7_PORT, AO_ADC_PIN7_PIN, STM_PUPDR_NONE); +#endif +#ifdef AO_ADC_PIN24_PORT + #error "Too many ADC ports" +#endif + + stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_ADCEN); + + chselr = 0; +#if AO_NUM_ADC > 0 + chselr |= (1 << AO_ADC_PIN0_CH); +#endif +#if AO_NUM_ADC > 1 + chselr |= (1 << AO_ADC_PIN1_CH); +#endif +#if AO_NUM_ADC > 2 + chselr |= (1 << AO_ADC_PIN2_CH); +#endif +#if AO_NUM_ADC > 3 + chselr |= (1 << AO_ADC_PIN3_CH); +#endif +#if AO_NUM_ADC > 4 + chselr |= (1 << AO_ADC_PIN4_CH); +#endif +#if AO_NUM_ADC > 5 + chselr |= (1 << AO_ADC_PIN5_CH); +#endif +#if AO_NUM_ADC > 6 + chselr |= (1 << AO_ADC_PIN6_CH); +#endif +#if AO_NUM_ADC > 7 + chselr |= (1 << AO_ADC_PIN7_CH); +#endif +#if AO_NUM_ADC > 8 +#error Need more ADC defines +#endif + + /* Wait for ADC to be idle */ + while (stm_adc.cr & ((1 << STM_ADC_CR_ADCAL) | + (1 << STM_ADC_CR_ADDIS))) + ; + + /* Disable */ + if (stm_adc.cr & (1 << STM_ADC_CR_ADEN)) { + stm_adc.cr |= (1 << STM_ADC_CR_ADDIS); + while (stm_adc.cr & (1 << STM_ADC_CR_ADDIS)) + ; + } + + /* Turn off everything */ + stm_adc.cr &= ~((1 << STM_ADC_CR_ADCAL) | + (1 << STM_ADC_CR_ADSTP) | + (1 << STM_ADC_CR_ADSTART) | + (1 << STM_ADC_CR_ADEN)); + + /* Configure */ + stm_adc.cfgr1 = ((0 << STM_ADC_CFGR1_AWDCH) | /* analog watchdog channel 0 */ + (0 << STM_ADC_CFGR1_AWDEN) | /* Disable analog watchdog */ + (0 << STM_ADC_CFGR1_AWDSGL) | /* analog watchdog on all channels */ + (0 << STM_ADC_CFGR1_DISCEN) | /* Not discontinuous mode. All channels converted with one trigger */ + (0 << STM_ADC_CFGR1_AUTOOFF) | /* Leave ADC running */ + (1 << STM_ADC_CFGR1_WAIT) | /* Wait for data to be read before next conversion */ + (0 << STM_ADC_CFGR1_CONT) | /* only one set of conversions per trigger */ + (1 << STM_ADC_CFGR1_OVRMOD) | /* overwrite on overrun */ + (STM_ADC_CFGR1_EXTEN_DISABLE << STM_ADC_CFGR1_EXTEN) | /* SW trigger */ + (0 << STM_ADC_CFGR1_ALIGN) | /* Align to LSB */ + (STM_ADC_CFGR1_RES_12 << STM_ADC_CFGR1_RES) | /* 12 bit resolution */ + (STM_ADC_CFGR1_SCANDIR_UP << STM_ADC_CFGR1_SCANDIR) | /* scan 0 .. n */ + (STM_ADC_CFGR1_DMACFG_ONESHOT << STM_ADC_CFGR1_DMACFG) | /* one set of conversions then stop */ + (1 << STM_ADC_CFGR1_DMAEN)); /* enable DMA */ + + /* Set the clock */ + stm_adc.cfgr2 = STM_ADC_CFGR2_CKMODE_PCLK_2 << STM_ADC_CFGR2_CKMODE; + + /* Shortest sample time */ + stm_adc.smpr = STM_ADC_SMPR_SMP_71_5 << STM_ADC_SMPR_SMP; + + stm_adc.chselr = chselr; + + stm_adc.ccr = ((0 << STM_ADC_CCR_VBATEN) | + (0 << STM_ADC_CCR_TSEN) | + (0 << STM_ADC_CCR_VREFEN)); + + /* Calibrate */ + stm_adc.cr |= (1 << STM_ADC_CR_ADCAL); + while ((stm_adc.cr & (1 << STM_ADC_CR_ADCAL)) != 0) + ; + + /* Enable */ + stm_adc.cr |= (1 << STM_ADC_CR_ADEN); + while ((stm_adc.isr & (1 << STM_ADC_ISR_ADRDY)) == 0) + ; + + /* Clear any stale status bits */ + stm_adc.isr = 0; + + /* Turn on syscfg */ + stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SYSCFGCOMPEN); + + /* Set ADC to use DMA channel 1 (option 1) */ + stm_syscfg.cfgr1 &= ~(1 << STM_SYSCFG_CFGR1_ADC_DMA_RMP); + + ao_dma_alloc(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1)); + + ao_cmd_register(&ao_adc_cmds[0]); + + ao_adc_ready = 1; +} diff --git a/src/stmf0/ao_beep_stm.c b/src/stmf0/ao_beep_stm.c new file mode 100644 index 00000000..fc83bb63 --- /dev/null +++ b/src/stmf0/ao_beep_stm.c @@ -0,0 +1,185 @@ +/* + * Copyright © 2012 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" + +#ifndef BEEPER_CHANNEL +#error BEEPER_CHANNEL undefined +#endif + +void +ao_beep(uint8_t beep) +{ + if (beep == 0) { + stm_tim1.cr1 = 0; + stm_tim1.bdtr = 0; + stm_rcc.apb2enr &= ~(1 << STM_RCC_APB2ENR_TIM1EN); + } else { + stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_TIM1EN); + + /* Master output enable */ + stm_tim1.bdtr = (1 << STM_TIM1_BDTR_MOE); + + stm_tim1.cr2 = ((0 << STM_TIM1_CR2_TI1S) | + (STM_TIM1_CR2_MMS_RESET << STM_TIM1_CR2_MMS) | + (0 << STM_TIM1_CR2_CCDS)); + + /* Set prescaler to match cc1111 clocks + */ + stm_tim1.psc = AO_TIM_CLK / 750000; + + /* 1. Select the counter clock (internal, external, prescaler). + * + * Setting SMCR to zero means use the internal clock + */ + + stm_tim1.smcr = 0; + + /* 2. Write the desired data in the TIMx_ARR and TIMx_CCRx registers. */ + stm_tim1.arr = beep; + stm_tim1.ccr1 = beep; + + /* 3. Set the CCxIE and/or CCxDE bits if an interrupt and/or a + * DMA request is to be generated. + */ + /* don't want this */ + + /* 4. Select the output mode. For example, you must write + * OCxM=011, OCxPE=0, CCxP=0 and CCxE=1 to toggle OCx output + * pin when CNT matches CCRx, CCRx preload is not used, OCx + * is enabled and active high. + */ + +#if BEEPER_CHANNEL == 1 + stm_tim1.ccmr1 = ((0 << STM_TIM1_CCMR1_OC2CE) | + (STM_TIM1_CCMR1_OCM_FROZEN << STM_TIM1_CCMR1_OC2M) | + (0 << STM_TIM1_CCMR1_OC2PE) | + (0 << STM_TIM1_CCMR1_OC2FE) | + (STM_TIM1_CCMR1_CCS_OUTPUT << STM_TIM1_CCMR1_CC2S) | + + (0 << STM_TIM1_CCMR1_OC1CE) | + (STM_TIM1_CCMR1_OCM_TOGGLE << STM_TIM1_CCMR1_OC1M) | + (0 << STM_TIM1_CCMR1_OC1PE) | + (0 << STM_TIM1_CCMR1_OC1FE) | + (STM_TIM1_CCMR1_CCS_OUTPUT << STM_TIM1_CCMR1_CC1S)); + + stm_tim1.ccer = ((0 << STM_TIM1_CCER_CC4P) | + (0 << STM_TIM1_CCER_CC4E) | + (0 << STM_TIM1_CCER_CC3NP) | + (0 << STM_TIM1_CCER_CC3NE) | + (0 << STM_TIM1_CCER_CC3P) | + (0 << STM_TIM1_CCER_CC3E) | + (0 << STM_TIM1_CCER_CC2NP) | + (0 << STM_TIM1_CCER_CC2NE) | + (0 << STM_TIM1_CCER_CC2P) | + (0 << STM_TIM1_CCER_CC2E) | + (0 << STM_TIM1_CCER_CC1NE) | + (0 << STM_TIM1_CCER_CC1P) | + (1 << STM_TIM1_CCER_CC1E)); +#endif +#if BEEPER_CHANNEL == 3 + stm_tim1.ccmr2 = ((0 << STM_TIM1_CCMR2_OC4CE) | + (STM_TIM1_CCMR_OCM_FROZEN << STM_TIM1_CCMR2_OC4M) | + (0 << STM_TIM1_CCMR2_OC4PE) | + (0 << STM_TIM1_CCMR2_OC4FE) | + (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR2_CC4S) | + + (0 << STM_TIM1_CCMR2_OC3CE) | + (STM_TIM1_CCMR_OCM_TOGGLE << STM_TIM1_CCMR2_OC3M) | + (0 << STM_TIM1_CCMR2_OC3PE) | + (0 << STM_TIM1_CCMR2_OC3FE) | + (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR2_CC3S)); + + stm_tim1.ccer = ((0 << STM_TIM1_CCER_CC4P) | + (0 << STM_TIM1_CCER_CC4E) | + (0 << STM_TIM1_CCER_CC3NP) | + (0 << STM_TIM1_CCER_CC3NE) | + (0 << STM_TIM1_CCER_CC3P) | + (1 << STM_TIM1_CCER_CC3E) | + (0 << STM_TIM1_CCER_CC2NP) | + (0 << STM_TIM1_CCER_CC2NE) | + (0 << STM_TIM1_CCER_CC2P) | + (0 << STM_TIM1_CCER_CC2E) | + (0 << STM_TIM1_CCER_CC1NE) | + (0 << STM_TIM1_CCER_CC1P) | + (0 << STM_TIM1_CCER_CC1E)); +#endif +#if BEEPER_CHANNEL == 4 + stm_tim1.ccmr2 = ((0 << STM_TIM1_CCMR2_OC4CE) | + (STM_TIM1_CCMR2_OC4M_TOGGLE << STM_TIM1_CCMR2_OC4M) | + (0 << STM_TIM1_CCMR2_OC4PE) | + (0 << STM_TIM1_CCMR2_OC4FE) | + (STM_TIM1_CCMR2_CC4S_OUTPUT << STM_TIM1_CCMR2_CC4S) | + + (0 << STM_TIM1_CCMR2_OC3CE) | + (STM_TIM1_CCMR2_OC3M_FROZEN << STM_TIM1_CCMR2_OC3M) | + (0 << STM_TIM1_CCMR2_OC3PE) | + (0 << STM_TIM1_CCMR2_OC3FE) | + (STM_TIM1_CCMR2_CC3S_OUTPUT << STM_TIM1_CCMR2_CC3S)); + + stm_tim1.ccer = ((0 << STM_TIM1_CCER_CC4NP) | + (0 << STM_TIM1_CCER_CC4P) | + (1 << STM_TIM1_CCER_CC4E) | + (0 << STM_TIM1_CCER_CC3NP) | + (0 << STM_TIM1_CCER_CC3P) | + (0 << STM_TIM1_CCER_CC3E) | + (0 << STM_TIM1_CCER_CC2NP) | + (0 << STM_TIM1_CCER_CC2P) | + (0 << STM_TIM1_CCER_CC2E) | + (0 << STM_TIM1_CCER_CC1NP) | + (0 << STM_TIM1_CCER_CC1P) | + (0 << STM_TIM1_CCER_CC1E)); +#endif + /* 5. Enable the counter by setting the CEN bit in the TIMx_CR1 register. */ + + stm_tim1.cr1 = ((STM_TIM1_CR1_CKD_1 << STM_TIM1_CR1_CKD) | + (0 << STM_TIM1_CR1_ARPE) | + (STM_TIM1_CR1_CMS_EDGE << STM_TIM1_CR1_CMS) | + (0 << STM_TIM1_CR1_DIR) | + (0 << STM_TIM1_CR1_OPM) | + (0 << STM_TIM1_CR1_URS) | + (0 << STM_TIM1_CR1_UDIS) | + (1 << STM_TIM1_CR1_CEN)); + + /* Update the values */ + stm_tim1.egr = (1 << STM_TIM1_EGR_UG); + } +} + +void +ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant +{ + ao_beep(beep); + ao_delay(ticks); + ao_beep(0); +} + +void +ao_beep_init(void) +{ +#if BEEPER_CHANNEL == 3 + /* Our beeper is on PA10, which is hooked to TIM1_CH3. + */ + ao_enable_port(&stm_gpioa); + stm_afr_set(&stm_gpioa, 10, STM_AFR_AF2); +#else +#error unknown beeper channel +#endif + /* Leave the timer off until requested */ + + stm_rcc.apb2enr &= ~(1 << STM_RCC_APB2ENR_TIM1EN); +} diff --git a/src/stmf0/ao_spi_stm_slave.c b/src/stmf0/ao_spi_stm_slave.c new file mode 100644 index 00000000..962ff2c6 --- /dev/null +++ b/src/stmf0/ao_spi_stm_slave.c @@ -0,0 +1,339 @@ +/* + * Copyright © 2012 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include + +struct ao_spi_stm_slave_info { + uint8_t miso_dma_index; + uint8_t mosi_dma_index; + struct stm_spi *stm_spi; +}; + +static uint8_t ao_spi_slave_mutex[STM_NUM_SPI]; +static uint8_t ao_spi_slave_index[STM_NUM_SPI]; + +static const struct ao_spi_stm_slave_info ao_spi_stm_slave_info[STM_NUM_SPI] = { + { + .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_RX), + .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_TX), + &stm_spi1 + }, + { + .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_RX), + .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_TX), + &stm_spi2 + } +}; + +static uint8_t spi_dev_null; + +void +ao_spi_slave_send(void *block, uint16_t len) +{ + struct stm_spi *stm_spi = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].stm_spi; + uint8_t mosi_dma_index = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].mosi_dma_index; + uint8_t miso_dma_index = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].miso_dma_index; + + /* Set up the transmit DMA to deliver data */ + ao_dma_set_transfer(mosi_dma_index, + &stm_spi->dr, + block, + len, + (0 << STM_DMA_CCR_MEM2MEM) | + (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) | + (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) | + (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) | + (1 << STM_DMA_CCR_MINC) | + (0 << STM_DMA_CCR_PINC) | + (0 << STM_DMA_CCR_CIRC) | + (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR)); + + /* Clear RXNE */ + (void) stm_spi->dr; + + /* Set up the receive DMA -- when this is done, we know the SPI unit + * is idle. Without this, we'd have to poll waiting for the BSY bit to + * be cleared + */ + ao_dma_set_transfer(miso_dma_index, + &stm_spi->dr, + &spi_dev_null, + len, + (0 << STM_DMA_CCR_MEM2MEM) | + (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) | + (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) | + (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) | + (0 << STM_DMA_CCR_MINC) | + (0 << STM_DMA_CCR_PINC) | + (0 << STM_DMA_CCR_CIRC) | + (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR)); + stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) | + (0 << STM_SPI_CR2_RXNEIE) | + (0 << STM_SPI_CR2_ERRIE) | + (0 << STM_SPI_CR2_SSOE) | + (1 << STM_SPI_CR2_TXDMAEN) | + (1 << STM_SPI_CR2_RXDMAEN)); + ao_dma_start(miso_dma_index); + ao_dma_start(mosi_dma_index); + ao_arch_critical( + while (!ao_dma_done[miso_dma_index]) + ao_sleep(&ao_dma_done[miso_dma_index]); + ); + ao_dma_done_transfer(mosi_dma_index); + ao_dma_done_transfer(miso_dma_index); +} + +uint8_t +ao_spi_slave_recv(void *block, uint16_t len) +{ + struct stm_spi *stm_spi = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].stm_spi; + uint8_t mosi_dma_index = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].mosi_dma_index; + uint8_t miso_dma_index = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].miso_dma_index; + + /* Set up transmit DMA to make the SPI hardware actually run */ + ao_dma_set_transfer(mosi_dma_index, + &stm_spi->dr, + &spi_dev_null, + len, + (0 << STM_DMA_CCR_MEM2MEM) | + (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) | + (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) | + (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) | + (0 << STM_DMA_CCR_MINC) | + (0 << STM_DMA_CCR_PINC) | + (0 << STM_DMA_CCR_CIRC) | + (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR)); + + /* Clear RXNE */ + (void) stm_spi->dr; + + /* Set up the receive DMA to capture data */ + ao_dma_set_transfer(miso_dma_index, + &stm_spi->dr, + block, + len, + (0 << STM_DMA_CCR_MEM2MEM) | + (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) | + (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) | + (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) | + (1 << STM_DMA_CCR_MINC) | + (0 << STM_DMA_CCR_PINC) | + (0 << STM_DMA_CCR_CIRC) | + (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR)); + + stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) | + (0 << STM_SPI_CR2_RXNEIE) | + (0 << STM_SPI_CR2_ERRIE) | + (0 << STM_SPI_CR2_SSOE) | + (1 << STM_SPI_CR2_TXDMAEN) | + (1 << STM_SPI_CR2_RXDMAEN)); + ao_dma_start(miso_dma_index); + ao_dma_start(mosi_dma_index); + + /* Wait until the SPI unit is done */ + ao_arch_critical( + while (!ao_dma_done[miso_dma_index]) + ao_sleep(&ao_dma_done[miso_dma_index]); + ); + + ao_dma_done_transfer(mosi_dma_index); + ao_dma_done_transfer(miso_dma_index); + return 1; +} + +static void +ao_spi_slave_disable_index(uint8_t spi_index) +{ + /* Disable current config + */ + switch (AO_SPI_INDEX(spi_index)) { + case STM_SPI_INDEX(1): + switch (spi_index) { + case AO_SPI_1_PA5_PA6_PA7: + stm_gpio_set(&stm_gpioa, 5, 1); + stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT); + stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT); + stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT); + break; + case AO_SPI_1_PB3_PB4_PB5: + stm_gpio_set(&stm_gpiob, 3, 1); + stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT); + stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT); + stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT); + break; + case AO_SPI_1_PE13_PE14_PE15: + stm_gpio_set(&stm_gpioe, 13, 1); + stm_moder_set(&stm_gpioe, 13, STM_MODER_OUTPUT); + stm_moder_set(&stm_gpioe, 14, STM_MODER_INPUT); + stm_moder_set(&stm_gpioe, 15, STM_MODER_OUTPUT); + break; + } + break; + case STM_SPI_INDEX(2): + switch (spi_index) { + case AO_SPI_2_PB13_PB14_PB15: + stm_gpio_set(&stm_gpiob, 13, 1); + stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT); + stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT); + stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT); + break; + case AO_SPI_2_PD1_PD3_PD4: + stm_gpio_set(&stm_gpiod, 1, 1); + stm_moder_set(&stm_gpiod, 1, STM_MODER_OUTPUT); + stm_moder_set(&stm_gpiod, 3, STM_MODER_INPUT); + stm_moder_set(&stm_gpiod, 4, STM_MODER_OUTPUT); + break; + } + break; + } +} + +static void +ao_spi_slave_enable_index(uint8_t spi_index) +{ + switch (AO_SPI_INDEX(spi_index)) { + case STM_SPI_INDEX(1): + switch (spi_index) { + case AO_SPI_1_PA5_PA6_PA7: + stm_afr_set(&stm_gpioa, 5, STM_AFR_AF5); + stm_afr_set(&stm_gpioa, 6, STM_AFR_AF5); + stm_afr_set(&stm_gpioa, 7, STM_AFR_AF5); + break; + case AO_SPI_1_PB3_PB4_PB5: + stm_afr_set(&stm_gpiob, 3, STM_AFR_AF5); + stm_afr_set(&stm_gpiob, 4, STM_AFR_AF5); + stm_afr_set(&stm_gpiob, 5, STM_AFR_AF5); + break; + case AO_SPI_1_PE13_PE14_PE15: + stm_afr_set(&stm_gpioe, 13, STM_AFR_AF5); + stm_afr_set(&stm_gpioe, 14, STM_AFR_AF5); + stm_afr_set(&stm_gpioe, 15, STM_AFR_AF5); + break; + } + break; + case STM_SPI_INDEX(2): + switch (spi_index) { + case AO_SPI_2_PB13_PB14_PB15: + stm_afr_set(&stm_gpiob, 13, STM_AFR_AF5); + stm_afr_set(&stm_gpiob, 14, STM_AFR_AF5); + stm_afr_set(&stm_gpiob, 15, STM_AFR_AF5); + break; + case AO_SPI_2_PD1_PD3_PD4: + stm_afr_set(&stm_gpiod, 1, STM_AFR_AF5); + stm_afr_set(&stm_gpiod, 3, STM_AFR_AF5); + stm_afr_set(&stm_gpiod, 4, STM_AFR_AF5); + break; + } + break; + } +} + +void +ao_spi_slave_get(uint8_t spi_index, uint32_t speed) +{ + uint8_t id = AO_SPI_INDEX(spi_index); + struct stm_spi *stm_spi = ao_spi_stm_slave_info[id].stm_spi; + + ao_mutex_get(&ao_spi_slave_mutex[id]); + stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) | /* Three wire mode */ + (0 << STM_SPI_CR1_BIDIOE) | + (0 << STM_SPI_CR1_CRCEN) | /* CRC disabled */ + (0 << STM_SPI_CR1_CRCNEXT) | + (0 << STM_SPI_CR1_DFF) | + (0 << STM_SPI_CR1_RXONLY) | + (1 << STM_SPI_CR1_SSM) | /* Software SS handling */ + (1 << STM_SPI_CR1_SSI) | /* ... */ + (0 << STM_SPI_CR1_LSBFIRST) | /* Big endian */ + (1 << STM_SPI_CR1_SPE) | /* Enable SPI unit */ + (speed << STM_SPI_CR1_BR) | /* baud rate to pclk/4 */ + (1 << STM_SPI_CR1_MSTR) | + (0 << STM_SPI_CR1_CPOL) | /* Format 0 */ + (0 << STM_SPI_CR1_CPHA)); + if (spi_index != ao_spi_slave_index[id]) { + + /* Disable old config + */ + ao_spi_slave_disable_index(ao_spi_slave_index[id]); + + /* Enable new config + */ + ao_spi_slave_enable_index(spi_index); + + /* Remember current config + */ + ao_spi_slave_index[id] = spi_index; + } +} + +void +ao_spi_slave_put(uint8_t spi_index) +{ + uint8_t id = AO_SPI_INDEX(spi_index); + struct stm_spi *stm_spi = ao_spi_stm_slave_info[id].stm_spi; + + stm_spi->cr1 = 0; + ao_mutex_put(&ao_spi_slave_mutex[id]); +} + +static void +ao_spi_channel_init(uint8_t spi_index) +{ + uint8_t id = AO_SPI_INDEX(spi_index); + struct stm_spi *stm_spi = ao_spi_stm_slave_info[id].stm_spi; + + ao_spi_slave_disable_index(spi_index); + + stm_spi->cr1 = 0; + (void) stm_spi->sr; + stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) | + (0 << STM_SPI_CR2_RXNEIE) | + (0 << STM_SPI_CR2_ERRIE) | + (0 << STM_SPI_CR2_SSOE) | + (0 << STM_SPI_CR2_TXDMAEN) | + (0 << STM_SPI_CR2_RXDMAEN)); +} + +void +ao_spi_slave_init(void) +{ +#if HAS_SPI_SLAVE_1 +# if SPI_1_PA5_PA6_PA7 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN); +# endif +# if SPI_1_PB3_PB4_PB5 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN); +# endif +# if SPI_1_PE13_PE14_PE15 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOEEN); +# endif + stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN); + ao_spi_slave_index[0] = AO_SPI_CONFIG_NONE; + ao_spi_channel_init(0); +#endif + +#if HAS_SPI_SLAVE_2 +# if SPI_2_PB13_PB14_PB15 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN); +# endif +# if SPI_2_PD1_PD3_PD4 + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN); +# endif + stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN); + ao_spi_slave_index[1] = AO_SPI_CONFIG_NONE; + ao_spi_channel_init(1); +#endif +} -- cgit v1.2.3 From 97c814bc12893bee40f9dc38fabbaa69e0dc6aed Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 28 Jan 2017 15:35:48 -0800 Subject: altos: Initial TeleMini v3.0 code For first prototype, which attempted to use the SoC clock for the radio. Signed-off-by: Keith Packard --- src/telemini-v3.0/ao_pins.h | 202 ++++++++++++++++++++++++++++++ src/telemini-v3.0/ao_telemini.c | 52 ++++++++ src/telemini-v3.0/ao_telemini_calibrate.c | 71 +++++++++++ 3 files changed, 325 insertions(+) create mode 100644 src/telemini-v3.0/ao_pins.h create mode 100644 src/telemini-v3.0/ao_telemini.c create mode 100644 src/telemini-v3.0/ao_telemini_calibrate.c (limited to 'src') diff --git a/src/telemini-v3.0/ao_pins.h b/src/telemini-v3.0/ao_pins.h new file mode 100644 index 00000000..e060b931 --- /dev/null +++ b/src/telemini-v3.0/ao_pins.h @@ -0,0 +1,202 @@ +/* + * Copyright © 2013 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#define HAS_BEEP 1 +#define HAS_BATTERY_REPORT 1 + +#define AO_STACK_SIZE 384 + +#define IS_FLASH_LOADER 0 + +/* 40MHz clock based on 16MHz reference */ +//#define AO_HSI48 1 +#define AO_HSE 16000000 +#define AO_RCC_CFGR_PLLMUL STM_RCC_CFGR_PLLMUL_5 +#define AO_RCC_CFGR2_PLLDIV STM_RCC_CFGR2_PREDIV_2 +#define AO_PLLMUL 5 +#define AO_PLLDIV 2 + +/* HCLK = 40MHz */ +#define AO_AHB_PRESCALER 1 +#define AO_RCC_CFGR_HPRE_DIV STM_RCC_CFGR_HPRE_DIV_1 + +/* APB = 40MHz */ +#define AO_APB_PRESCALER 1 +#define AO_RCC_CFGR_PPRE_DIV STM_RCC_CFGR_PPRE_DIV_1 + +/* Send PLL clock to cc1200 */ +#define AO_MCO_PORT (&stm_gpioa) +#define AO_MCO_PIN 9 +#define AO_MCO_AF STM_AFR_AF5 + +#define HAS_USB 0 +#define AO_USB_DIRECTIO 0 +#define AO_PA11_PA12_RMP 0 + +#define PACKET_HAS_SLAVE 1 + +#define AO_LOG_FORMAT AO_LOG_FORMAT_EASYMINI + +#define HAS_BOOT_RADIO 0 + +#define HAS_ACCEL 0 +#define HAS_GPS 0 +#define HAS_RADIO 1 +#define HAS_RADIO_RATE 1 +#define HAS_FLIGHT 1 +#define HAS_EEPROM 1 +#define HAS_TELEMETRY 1 +#define HAS_APRS 0 +#define HAS_LOG 1 +#define USE_INTERNAL_FLASH 0 +#define HAS_IGNITE 1 +#define HAS_IGNITE_REPORT 1 + +/* Beeper is on Tim1 CH3 */ +#define BEEPER_CHANNEL 3 + +/* LED */ +#define LED_PORT_ENABLE STM_RCC_AHBENR_IOPAEN +#define LED_PORT (&stm_gpioa) +#define LED_PIN_GREEN 15 +#define AO_LED_GREEN (1 << 15) +#define AO_LED_PANIC AO_LED_GREEN + +#define LEDS_AVAILABLE AO_LED_GREEN + +/* USART */ + +#define HAS_SERIAL 0 +#define USE_SERIAL_0_STDIN 1 +#define SERIAL_0_18_19 1 +#define SERIAL_0_14_15 0 +#define SERIAL_0_17_18 0 +#define SERIAL_0_26_27 0 + +/* SPI */ + +#define HAS_SPI_0 1 +#define SPI_SCK0_P0_6 1 +#define HAS_SPI_1 1 +#define SPI_SCK1_P1_15 1 +#define SPI_MISO1_P0_22 1 +#define SPI_MOSI1_P0_21 1 + +/* M25 */ + +#define M25_MAX_CHIPS 1 +#define AO_M25_SPI_CS_PORT (&stm_gpioa) +#define AO_M25_SPI_CS_MASK (1 << 3) +#define AO_M25_SPI_BUS AO_SPI_1_PA5_PA6_PA7 + +/* MS5607 */ + +#define HAS_MS5607 1 +#define HAS_MS5611 0 +#define AO_MS5607_PRIVATE_PINS 0 +#define AO_MS5607_CS_PORT (&stm_gpioa) +#define AO_MS5607_CS_PIN 4 +#define AO_MS5607_CS_MASK (1 << AO_MS5607_CS_PIN) +#define AO_MS5607_MISO_PORT (&stm_gpiob) +#define AO_MS5607_MISO_PIN 4 +#define AO_MS5607_MISO_MASK (1 << AO_MS5607_MISO_PIN) +#define AO_MS5607_SPI_INDEX AO_SPI_1_PB3_PB4_PB5 + +/* CC1200 */ + +// #define AO_RADIO_CAL_DEFAULT 5695733 +#define AO_RADIO_CAL_DEFAULT 5695947 + +#define AO_FEC_DEBUG 0 +#define AO_CC1200_SPI_CS_PORT (&stm_gpiob) +#define AO_CC1200_SPI_CS_PIN 0 +#define AO_CC1200_SPI_BUS AO_SPI_1_PA5_PA6_PA7 +#define AO_CC1200_SPI stm_spi1 + +#define AO_CC1200_INT_PORT (&stm_gpiob) +#define AO_CC1200_INT_PIN 1 + +#define AO_CC1200_INT_GPIO 2 +#define AO_CC1200_INT_GPIO_IOCFG CC1200_IOCFG2 + + +#define AO_DATA_RING 16 + +/* + * ADC + */ + +#define HAS_ADC 1 + +#define AO_ADC_PIN0_PORT (&stm_gpioa) +#define AO_ADC_PIN0_PIN 0 +#define AO_ADC_PIN0_CH 0 +#define AO_ADC_PIN1_PORT (&stm_gpioa) +#define AO_ADC_PIN1_PIN 1 +#define AO_ADC_PIN1_CH 1 +#define AO_ADC_PIN2_PORT (&stm_gpioa) +#define AO_ADC_PIN2_PIN 2 +#define AO_ADC_PIN2_CH 2 + +#define AO_ADC_RCC_AHBENR ((1 << STM_RCC_AHBENR_IOPAEN)) + +#define AO_NUM_ADC 3 + +struct ao_adc { + int16_t sense_a; + int16_t sense_m; + int16_t v_batt; +}; + +/* + * Igniter + */ + +#define AO_IGNITER_CLOSED 400 +#define AO_IGNITER_OPEN 60 + +#define AO_IGNITER_DROGUE_PORT (&stm_gpiob) +#define AO_IGNITER_DROGUE_PIN 7 +#define AO_IGNITER_SET_DROGUE(v) ao_gpio_set(AO_IGNITER_DROGUE_PORT, AO_IGNITER_DROGUE_PIN, AO_IGNITER_DROGUE, v) + +#define AO_IGNITER_MAIN_PORT (&stm_gpiob) +#define AO_IGNITER_MAIN_PIN 6 +#define AO_IGNITER_SET_MAIN(v) ao_gpio_set(AO_IGNITER_MAIN_PORT, AO_IGNITER_MAIN_PIN, AO_IGNITER_MAIN, v) + +#define AO_SENSE_DROGUE(p) ((p)->adc.sense_a) +#define AO_SENSE_MAIN(p) ((p)->adc.sense_m) + +#define AO_ADC_DUMP(p) \ + printf("tick: %5u apogee: %5d main: %5d batt: %5d\n", \ + (p)->tick, (p)->adc.sense_a, (p)->adc.sense_m, (p)->adc.v_batt) + +/* + * Voltage divider on ADC battery sampler + */ +#define AO_BATTERY_DIV_PLUS 100 /* 100k */ +#define AO_BATTERY_DIV_MINUS 27 /* 27k */ + +/* + * Voltage divider on ADC igniter samplers + */ +#define AO_IGNITE_DIV_PLUS 100 /* 100k */ +#define AO_IGNITE_DIV_MINUS 27 /* 27k */ + +/* + * ADC reference in decivolts + */ +#define AO_ADC_REFERENCE_DV 33 diff --git a/src/telemini-v3.0/ao_telemini.c b/src/telemini-v3.0/ao_telemini.c new file mode 100644 index 00000000..a0c0aa7c --- /dev/null +++ b/src/telemini-v3.0/ao_telemini.c @@ -0,0 +1,52 @@ +/* + * Copyright © 2011 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include + +void +main(void) +{ + ao_clock_init(); + ao_task_init(); + ao_led_init(LEDS_AVAILABLE); + ao_led_on(AO_LED_GREEN); + ao_timer_init(); + + ao_dma_init(); + ao_spi_init(); + ao_exti_init(); + + ao_adc_init(); + + ao_beep_init(); + ao_cmd_init(); + + ao_ms5607_init(); + + ao_storage_init(); + ao_flight_init(); + ao_log_init(); + ao_report_init(); + ao_telemetry_init(); + ao_radio_init(); + ao_packet_slave_init(TRUE); + ao_igniter_init(); + ao_config_init(); + + ao_start_scheduler(); +} diff --git a/src/telemini-v3.0/ao_telemini_calibrate.c b/src/telemini-v3.0/ao_telemini_calibrate.c new file mode 100644 index 00000000..7a9d7986 --- /dev/null +++ b/src/telemini-v3.0/ao_telemini_calibrate.c @@ -0,0 +1,71 @@ +/* + * Copyright © 2011 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include + +static void +ao_cal(void) +{ + ao_config_get(); + ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(500)); + for (;;) { + ao_led_on(AO_LED_GREEN); + ao_radio_test_on(); + ao_delay(AO_SEC_TO_TICKS(30)); + ao_led_off(AO_LED_GREEN); + ao_radio_test_off(); + ao_delay(AO_SEC_TO_TICKS(5)); + } +} + +static struct ao_task ao_cal_task; + +void +main(void) +{ + ao_clock_init(); + ao_task_init(); + ao_led_init(LEDS_AVAILABLE); + ao_led_on(AO_LED_GREEN); + ao_timer_init(); + + ao_dma_init(); + ao_spi_init(); + ao_exti_init(); + +// ao_adc_init(); + ao_beep_init(); +// ao_cmd_init(); +// ao_ms5607_init(); + + ao_storage_init(); +// ao_flight_init(); +// ao_log_init(); +// ao_report_init(); +// ao_telemetry_init(); + + ao_radio_init(); +// ao_packet_slave_init(TRUE); +// ao_igniter_init(); + + ao_config_init(); + + ao_add_task(&ao_cal_task, ao_cal, "radio_cal"); + + ao_start_scheduler(); +} -- cgit v1.2.3 From efdeb402d04e7f04ad4bd2764f8f1ca7270b3dff Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 3 Feb 2017 06:52:57 +0100 Subject: altos/telemini-v3.0: Update to second prototype version Separate radio xtal means we run the processor at 48MHz. Fix the battery monitoring voltage divider resistor values. Disable most of the code until we've got the radio working. Signed-off-by: Keith Packard --- src/telemini-v3.0/ao_pins.h | 27 +++++++++++---------------- src/telemini-v3.0/ao_telemini.c | 14 ++++++++------ 2 files changed, 19 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/telemini-v3.0/ao_pins.h b/src/telemini-v3.0/ao_pins.h index e060b931..6672a8da 100644 --- a/src/telemini-v3.0/ao_pins.h +++ b/src/telemini-v3.0/ao_pins.h @@ -20,17 +20,19 @@ #define AO_STACK_SIZE 384 +#define RELOCATE_INTERRUPT 0 + #define IS_FLASH_LOADER 0 -/* 40MHz clock based on 16MHz reference */ +/* 48MHz clock based on 16MHz reference */ //#define AO_HSI48 1 #define AO_HSE 16000000 -#define AO_RCC_CFGR_PLLMUL STM_RCC_CFGR_PLLMUL_5 -#define AO_RCC_CFGR2_PLLDIV STM_RCC_CFGR2_PREDIV_2 -#define AO_PLLMUL 5 -#define AO_PLLDIV 2 +#define AO_RCC_CFGR_PLLMUL STM_RCC_CFGR_PLLMUL_3 +#define AO_RCC_CFGR2_PLLDIV STM_RCC_CFGR2_PREDIV_1 +#define AO_PLLMUL 3 +#define AO_PLLDIV 1 -/* HCLK = 40MHz */ +/* HCLK = 48MHz */ #define AO_AHB_PRESCALER 1 #define AO_RCC_CFGR_HPRE_DIV STM_RCC_CFGR_HPRE_DIV_1 @@ -38,11 +40,6 @@ #define AO_APB_PRESCALER 1 #define AO_RCC_CFGR_PPRE_DIV STM_RCC_CFGR_PPRE_DIV_1 -/* Send PLL clock to cc1200 */ -#define AO_MCO_PORT (&stm_gpioa) -#define AO_MCO_PIN 9 -#define AO_MCO_AF STM_AFR_AF5 - #define HAS_USB 0 #define AO_USB_DIRECTIO 0 #define AO_PA11_PA12_RMP 0 @@ -89,8 +86,6 @@ /* SPI */ -#define HAS_SPI_0 1 -#define SPI_SCK0_P0_6 1 #define HAS_SPI_1 1 #define SPI_SCK1_P1_15 1 #define SPI_MISO1_P0_22 1 @@ -119,7 +114,7 @@ /* CC1200 */ // #define AO_RADIO_CAL_DEFAULT 5695733 -#define AO_RADIO_CAL_DEFAULT 5695947 +#define AO_RADIO_CAL_DEFAULT 5695717 #define AO_FEC_DEBUG 0 #define AO_CC1200_SPI_CS_PORT (&stm_gpiob) @@ -187,8 +182,8 @@ struct ao_adc { /* * Voltage divider on ADC battery sampler */ -#define AO_BATTERY_DIV_PLUS 100 /* 100k */ -#define AO_BATTERY_DIV_MINUS 27 /* 27k */ +#define AO_BATTERY_DIV_PLUS 56 /* 5.6k */ +#define AO_BATTERY_DIV_MINUS 100 /* 10k */ /* * Voltage divider on ADC igniter samplers diff --git a/src/telemini-v3.0/ao_telemini.c b/src/telemini-v3.0/ao_telemini.c index a0c0aa7c..d5fbb04e 100644 --- a/src/telemini-v3.0/ao_telemini.c +++ b/src/telemini-v3.0/ao_telemini.c @@ -36,17 +36,19 @@ main(void) ao_beep_init(); ao_cmd_init(); - ao_ms5607_init(); +// ao_ms5607_init(); ao_storage_init(); - ao_flight_init(); - ao_log_init(); - ao_report_init(); - ao_telemetry_init(); +// ao_flight_init(); +// ao_log_init(); +// ao_report_init(); +// ao_telemetry_init(); ao_radio_init(); ao_packet_slave_init(TRUE); - ao_igniter_init(); +// ao_igniter_init(); ao_config_init(); + ao_flight_force_idle = TRUE; + ao_start_scheduler(); } -- cgit v1.2.3 From c75736c9cd8f869c257a3024efda843cf0edf2a3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 18 Feb 2017 22:56:49 -0800 Subject: altos/telemini-v3.0: Finish initial turn-on TeleMini v3.0 is nearly working; there are some ADC issues still, and lots of altosui work left to decode the new telemetry packet. Signed-off-by: Keith Packard --- src/telemini-v3.0/ao_pins.h | 26 +++++++++++++++----------- src/telemini-v3.0/ao_telemini.c | 19 +++++++++++-------- src/telemini-v3.0/ao_telemini_calibrate.c | 9 +++++++++ 3 files changed, 35 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/telemini-v3.0/ao_pins.h b/src/telemini-v3.0/ao_pins.h index 6672a8da..031c1d18 100644 --- a/src/telemini-v3.0/ao_pins.h +++ b/src/telemini-v3.0/ao_pins.h @@ -16,9 +16,11 @@ */ #define HAS_BEEP 1 +#define HAS_SERIAL_1 0 #define HAS_BATTERY_REPORT 1 +#define HAS_BOOT_LOADER 0 -#define AO_STACK_SIZE 384 +#define AO_STACK_SIZE 448 #define RELOCATE_INTERRUPT 0 @@ -72,24 +74,23 @@ #define LED_PIN_GREEN 15 #define AO_LED_GREEN (1 << 15) #define AO_LED_PANIC AO_LED_GREEN +#define AO_LED_LOW AO_LED_GREEN +#define AO_LED_MID AO_LED_GREEN #define LEDS_AVAILABLE AO_LED_GREEN -/* USART */ +/* Serial. Hooked to the spare pin (PA9/19) and the beeper (PA10/20) */ -#define HAS_SERIAL 0 -#define USE_SERIAL_0_STDIN 1 -#define SERIAL_0_18_19 1 -#define SERIAL_0_14_15 0 -#define SERIAL_0_17_18 0 -#define SERIAL_0_26_27 0 +#define SERIAL_1_PA9_PA10 1 +#define USE_SERIAL_1_STDIN HAS_SERIAL_1 +#define DELAY_SERIAL_1_STDIN 0 /* SPI */ #define HAS_SPI_1 1 -#define SPI_SCK1_P1_15 1 -#define SPI_MISO1_P0_22 1 -#define SPI_MOSI1_P0_21 1 +#define SPI_1_PA5_PA6_PA7 1 +#define SPI_1_PB3_PB4_PB5 1 +#define SPI_1_OSPEEDR STM_OSPEEDR_MEDIUM /* M25 */ @@ -110,6 +111,7 @@ #define AO_MS5607_MISO_PIN 4 #define AO_MS5607_MISO_MASK (1 << AO_MS5607_MISO_PIN) #define AO_MS5607_SPI_INDEX AO_SPI_1_PB3_PB4_PB5 +#define AO_MS5607_SPI_SPEED AO_SPI_SPEED_12MHz /* CC1200 */ @@ -117,10 +119,12 @@ #define AO_RADIO_CAL_DEFAULT 5695717 #define AO_FEC_DEBUG 0 +#define CC1200_DEBUG 0 #define AO_CC1200_SPI_CS_PORT (&stm_gpiob) #define AO_CC1200_SPI_CS_PIN 0 #define AO_CC1200_SPI_BUS AO_SPI_1_PA5_PA6_PA7 #define AO_CC1200_SPI stm_spi1 +#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_12MHz #define AO_CC1200_INT_PORT (&stm_gpiob) #define AO_CC1200_INT_PIN 1 diff --git a/src/telemini-v3.0/ao_telemini.c b/src/telemini-v3.0/ao_telemini.c index d5fbb04e..c2c13236 100644 --- a/src/telemini-v3.0/ao_telemini.c +++ b/src/telemini-v3.0/ao_telemini.c @@ -33,22 +33,25 @@ main(void) ao_adc_init(); +#if HAS_BEEP ao_beep_init(); +#endif +#if HAS_SERIAL_1 + ao_serial_init(); +#endif ao_cmd_init(); -// ao_ms5607_init(); + ao_ms5607_init(); ao_storage_init(); -// ao_flight_init(); -// ao_log_init(); -// ao_report_init(); -// ao_telemetry_init(); + ao_flight_init(); + ao_log_init(); + ao_report_init(); + ao_telemetry_init(); ao_radio_init(); ao_packet_slave_init(TRUE); -// ao_igniter_init(); + ao_igniter_init(); ao_config_init(); - ao_flight_force_idle = TRUE; - ao_start_scheduler(); } diff --git a/src/telemini-v3.0/ao_telemini_calibrate.c b/src/telemini-v3.0/ao_telemini_calibrate.c index 7a9d7986..461810f0 100644 --- a/src/telemini-v3.0/ao_telemini_calibrate.c +++ b/src/telemini-v3.0/ao_telemini_calibrate.c @@ -22,7 +22,11 @@ static void ao_cal(void) { ao_config_get(); +#if HAS_BEEP ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(500)); +#else + ao_led_for(AO_LED_MID, AO_MS_TO_TICKS(500)); +#endif for (;;) { ao_led_on(AO_LED_GREEN); ao_radio_test_on(); @@ -49,7 +53,12 @@ main(void) ao_exti_init(); // ao_adc_init(); +#if HAS_BEEP ao_beep_init(); +#endif +#if HAS_SERIAL_1 + ao_serial_init(); +#endif // ao_cmd_init(); // ao_ms5607_init(); -- cgit v1.2.3 From 59ac667c4ae14e0fa699fb0f398d31763a237646 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 19 Feb 2017 17:39:21 -0800 Subject: altos: Split out TeleMini v3 log/telem labeling Allow the ground software to know which TeleMini version is in use, even though they are very similar with only ADC values differing. Signed-off-by: Keith Packard --- src/kernel/ao_log.h | 3 ++- src/kernel/ao_telemetry.c | 2 +- src/kernel/ao_telemetry.h | 3 ++- src/telemini-v2.0/ao_pins.h | 4 ++-- src/telemini-v3.0/ao_pins.h | 4 +++- 5 files changed, 10 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/kernel/ao_log.h b/src/kernel/ao_log.h index 13eb05bf..ad28e5ca 100644 --- a/src/kernel/ao_log.h +++ b/src/kernel/ao_log.h @@ -47,10 +47,11 @@ extern __pdata enum ao_flight_state ao_log_state; #define AO_LOG_FORMAT_TELEMEGA_OLD 5 /* 32 byte typed telemega records */ #define AO_LOG_FORMAT_EASYMINI 6 /* 16-byte MS5607 baro only, 3.0V supply */ #define AO_LOG_FORMAT_TELEMETRUM 7 /* 16-byte typed telemetrum records */ -#define AO_LOG_FORMAT_TELEMINI 8 /* 16-byte MS5607 baro only, 3.3V supply */ +#define AO_LOG_FORMAT_TELEMINI2 8 /* 16-byte MS5607 baro only, 3.3V supply, cc1111 SoC */ #define AO_LOG_FORMAT_TELEGPS 9 /* 32 byte telegps records */ #define AO_LOG_FORMAT_TELEMEGA 10 /* 32 byte typed telemega records with 32 bit gyro cal */ #define AO_LOG_FORMAT_DETHERM 11 /* 16-byte MS5607 baro only, no ADC */ +#define AO_LOG_FORMAT_TELEMINI3 12 /* 16-byte MS5607 baro only, 3.3V supply, stm32f042 SoC */ #define AO_LOG_FORMAT_NONE 127 /* No log at all */ extern __code uint8_t ao_log_format; diff --git a/src/kernel/ao_telemetry.c b/src/kernel/ao_telemetry.c index 15085bf4..fa817824 100644 --- a/src/kernel/ao_telemetry.c +++ b/src/kernel/ao_telemetry.c @@ -270,7 +270,7 @@ ao_send_mini(void) __xdata struct ao_data *packet = (__xdata struct ao_data *) &ao_data_ring[ao_data_ring_prev(ao_sample_data)]; telemetry.generic.tick = packet->tick; - telemetry.generic.type = AO_TELEMETRY_MINI; + telemetry.generic.type = AO_SEND_MINI; telemetry.mini.state = ao_flight_state; diff --git a/src/kernel/ao_telemetry.h b/src/kernel/ao_telemetry.h index c0f5e3c5..45aaeb07 100644 --- a/src/kernel/ao_telemetry.h +++ b/src/kernel/ao_telemetry.h @@ -270,7 +270,8 @@ struct ao_telemetry_metrum_data { /* 32 */ }; -#define AO_TELEMETRY_MINI 0x10 +#define AO_TELEMETRY_MINI2 0x10 /* CC1111 based */ +#define AO_TELEMETRY_MINI3 0x11 /* STMF042 based */ struct ao_telemetry_mini { uint16_t serial; /* 0 */ diff --git a/src/telemini-v2.0/ao_pins.h b/src/telemini-v2.0/ao_pins.h index 4f1d36df..d2aa4c2d 100644 --- a/src/telemini-v2.0/ao_pins.h +++ b/src/telemini-v2.0/ao_pins.h @@ -115,8 +115,8 @@ #define AO_IGNITER_FIRE_TIME AO_MS_TO_TICKS(50) #define AO_IGNITER_CHARGE_TIME AO_MS_TO_TICKS(2000) -#define AO_SEND_MINI -#define AO_LOG_FORMAT AO_LOG_FORMAT_TELEMINI +#define AO_SEND_MINI AO_TELEMETRY_MINI2 +#define AO_LOG_FORMAT AO_LOG_FORMAT_TELEMINI2 /* * ADC diff --git a/src/telemini-v3.0/ao_pins.h b/src/telemini-v3.0/ao_pins.h index 031c1d18..b4f2a630 100644 --- a/src/telemini-v3.0/ao_pins.h +++ b/src/telemini-v3.0/ao_pins.h @@ -48,7 +48,8 @@ #define PACKET_HAS_SLAVE 1 -#define AO_LOG_FORMAT AO_LOG_FORMAT_EASYMINI +#define AO_LOG_FORMAT AO_LOG_FORMAT_TELEMINI3 +#define AO_CONFIG_DEFAULT_FLIGHT_LOG_MAX ((uint32_t) 112 * (uint32_t) 1024) #define HAS_BOOT_RADIO 0 @@ -59,6 +60,7 @@ #define HAS_FLIGHT 1 #define HAS_EEPROM 1 #define HAS_TELEMETRY 1 +#define AO_SEND_MINI AO_TELEMETRY_MINI3 #define HAS_APRS 0 #define HAS_LOG 1 #define USE_INTERNAL_FLASH 0 -- cgit v1.2.3 From 5c272d8e50d0b23f31a6a9ebdad81fc514936222 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 19 Feb 2017 17:40:28 -0800 Subject: altos/telemini-v3.0: Swap main and apogee sense pins. These were just hooked up wrong in the software. Signed-off-by: Keith Packard --- src/telemini-v3.0/ao_pins.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/telemini-v3.0/ao_pins.h b/src/telemini-v3.0/ao_pins.h index b4f2a630..be7fd8d0 100644 --- a/src/telemini-v3.0/ao_pins.h +++ b/src/telemini-v3.0/ao_pins.h @@ -143,13 +143,13 @@ #define HAS_ADC 1 -#define AO_ADC_PIN0_PORT (&stm_gpioa) +#define AO_ADC_PIN0_PORT (&stm_gpioa) /* sense_m */ #define AO_ADC_PIN0_PIN 0 #define AO_ADC_PIN0_CH 0 -#define AO_ADC_PIN1_PORT (&stm_gpioa) +#define AO_ADC_PIN1_PORT (&stm_gpioa) /* sense_a */ #define AO_ADC_PIN1_PIN 1 #define AO_ADC_PIN1_CH 1 -#define AO_ADC_PIN2_PORT (&stm_gpioa) +#define AO_ADC_PIN2_PORT (&stm_gpioa) /* v_batt */ #define AO_ADC_PIN2_PIN 2 #define AO_ADC_PIN2_CH 2 @@ -158,8 +158,8 @@ #define AO_NUM_ADC 3 struct ao_adc { - int16_t sense_a; int16_t sense_m; + int16_t sense_a; int16_t v_batt; }; -- cgit v1.2.3 From 61f729567ff6355ab52c3e83399761103022a41a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 17 Dec 2016 20:57:38 -0800 Subject: altos/cc1111: Remove unneeded initialization in ao_timer.c The timers are all stopped when the chip boots, so no need to stop them. This saves some text space, allowing the current code to (just barely) fit. Signed-off-by: Keith Packard --- src/cc1111/ao_timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cc1111/ao_timer.c b/src/cc1111/ao_timer.c index 0acef562..a3d454da 100644 --- a/src/cc1111/ao_timer.c +++ b/src/cc1111/ao_timer.c @@ -62,7 +62,7 @@ ao_timer_init(void) /* NOTE: This uses a timer only present on cc1111 architecture. */ /* disable timer 1 */ - T1CTL = 0; +/* T1CTL = 0; */ /* set the sample rate */ T1CC0H = T1_SAMPLE_TIME >> 8; -- cgit v1.2.3 From 992eee8e0b4c6c774f3355af107fb422019ff4e5 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 20 Nov 2016 20:56:01 -0800 Subject: altos: Don't wait while idle if trying to minimize interrupt latency Keeping the scanout running reasonably means keeping interrupt latency constant, and that requires leaving the CPU running. Don't wait for interrupts when the system is running in this mode. Signed-off-by: Keith Packard --- src/kernel/ao_task.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/kernel/ao_task.c b/src/kernel/ao_task.c index e8a092aa..de23ea02 100644 --- a/src/kernel/ao_task.c +++ b/src/kernel/ao_task.c @@ -373,7 +373,11 @@ ao_yield(void) ao_arch_naked_define if (!ao_list_is_empty(&run_queue)) break; /* Wait for interrupts when there's nothing ready */ - ao_arch_wait_interrupt(); + if (ao_task_minimize_latency) { + ao_arch_release_interrupts(); + ao_arch_block_interrupts(); + } else + ao_arch_wait_interrupt(); } ao_cur_task = ao_list_first_entry(&run_queue, struct ao_task, queue); #else -- cgit v1.2.3 From 088ddbb177efc8be2fc467524dc1668553080d3b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 20 Nov 2016 20:54:10 -0800 Subject: altos/stm: Interrupt priority is in the upper bits of the priority mask Because the STM32L only offers 16 priority levels, the bottom four bits of each priority mask are not used. All of the interrupt priority settings in the system were using values < 16, making them all effectively the same. Fix that by moving them into the upper 4 bits and using symbolic constants everywhere. Signed-off-by: Keith Packard --- src/stm/ao_arch.h | 10 ++++++---- src/stm/ao_dma_stm.c | 3 ++- src/stm/ao_exti_stm.c | 2 +- src/stm/ao_serial_stm.c | 6 +++--- src/stm/ao_timer.c | 1 + src/stm/ao_usb_stm.c | 2 +- 6 files changed, 14 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/stm/ao_arch.h b/src/stm/ao_arch.h index 0cc29376..3d09af3c 100644 --- a/src/stm/ao_arch.h +++ b/src/stm/ao_arch.h @@ -122,10 +122,12 @@ extern const uint32_t ao_radio_cal; #define AO_TIM91011_CLK (2 * AO_PCLK2) #endif -#define AO_STM_NVIC_HIGH_PRIORITY 4 -#define AO_STM_NVIC_CLOCK_PRIORITY 6 -#define AO_STM_NVIC_MED_PRIORITY 8 -#define AO_STM_NVIC_LOW_PRIORITY 10 +/* The stm32l implements only 4 bits of the priority fields */ + +#define AO_STM_NVIC_HIGH_PRIORITY 0x40 +#define AO_STM_NVIC_MED_PRIORITY 0x80 +#define AO_STM_NVIC_LOW_PRIORITY 0xC0 +#define AO_STM_NVIC_CLOCK_PRIORITY 0xf0 void ao_lcd_stm_init(void); diff --git a/src/stm/ao_dma_stm.c b/src/stm/ao_dma_stm.c index 6d779660..63d6688a 100644 --- a/src/stm/ao_dma_stm.c +++ b/src/stm/ao_dma_stm.c @@ -155,7 +155,8 @@ ao_dma_init(void) for (index = 0; index < STM_NUM_DMA; index++) { stm_nvic_set_enable(STM_ISR_DMA1_CHANNEL1_POS + index); - stm_nvic_set_priority(STM_ISR_DMA1_CHANNEL1_POS + index, 4); + stm_nvic_set_priority(STM_ISR_DMA1_CHANNEL1_POS + index, + AO_STM_NVIC_MED_PRIORITY); ao_dma_allocated[index] = 0; ao_dma_mutex[index] = 0; } diff --git a/src/stm/ao_exti_stm.c b/src/stm/ao_exti_stm.c index 3e0b3e5c..2491b609 100644 --- a/src/stm/ao_exti_stm.c +++ b/src/stm/ao_exti_stm.c @@ -123,7 +123,7 @@ ao_exti_set_mode(struct stm_gpio *gpio, uint8_t pin, uint8_t mode) { (void) gpio; uint32_t mask = 1 << pin; - + if (mode & AO_EXTI_MODE_RISING) stm_exti.rtsr |= mask; else diff --git a/src/stm/ao_serial_stm.c b/src/stm/ao_serial_stm.c index db0be992..c625471e 100644 --- a/src/stm/ao_serial_stm.c +++ b/src/stm/ao_serial_stm.c @@ -444,7 +444,7 @@ ao_serial_init(void) ao_usart_init(&ao_stm_usart1); stm_nvic_set_enable(STM_ISR_USART1_POS); - stm_nvic_set_priority(STM_ISR_USART1_POS, 4); + stm_nvic_set_priority(STM_ISR_USART1_POS, AO_STM_NVIC_MED_PRIORITY); #if USE_SERIAL_1_STDIN && !DELAY_SERIAL_1_STDIN ao_add_stdio(_ao_serial1_pollchar, ao_serial1_putchar, @@ -500,7 +500,7 @@ ao_serial_init(void) #endif stm_nvic_set_enable(STM_ISR_USART2_POS); - stm_nvic_set_priority(STM_ISR_USART2_POS, 4); + stm_nvic_set_priority(STM_ISR_USART2_POS, AO_STM_NVIC_MED_PRIORITY); #if USE_SERIAL_2_STDIN && !DELAY_SERIAL_2_STDIN ao_add_stdio(_ao_serial2_pollchar, ao_serial2_putchar, @@ -544,7 +544,7 @@ ao_serial_init(void) ao_usart_init(&ao_stm_usart3); stm_nvic_set_enable(STM_ISR_USART3_POS); - stm_nvic_set_priority(STM_ISR_USART3_POS, 4); + stm_nvic_set_priority(STM_ISR_USART3_POS, AO_STM_NVIC_MED_PRIORITY); #if USE_SERIAL_3_STDIN && !DELAY_SERIAL_3_STDIN ao_add_stdio(_ao_serial3_pollchar, ao_serial3_putchar, diff --git a/src/stm/ao_timer.c b/src/stm/ao_timer.c index f86a5116..1576a6c9 100644 --- a/src/stm/ao_timer.c +++ b/src/stm/ao_timer.c @@ -90,6 +90,7 @@ ao_timer_init(void) stm_systick.csr = ((1 << STM_SYSTICK_CSR_ENABLE) | (1 << STM_SYSTICK_CSR_TICKINT) | (STM_SYSTICK_CSR_CLKSOURCE_HCLK_8 << STM_SYSTICK_CSR_CLKSOURCE)); + stm_nvic.shpr15_12 |= AO_STM_NVIC_CLOCK_PRIORITY << 24; } #endif diff --git a/src/stm/ao_usb_stm.c b/src/stm/ao_usb_stm.c index 9d72844e..2abaf10f 100644 --- a/src/stm/ao_usb_stm.c +++ b/src/stm/ao_usb_stm.c @@ -1015,7 +1015,7 @@ ao_usb_enable(void) ao_arch_block_interrupts(); /* Route interrupts */ - stm_nvic_set_priority(STM_ISR_USB_LP_POS, 3); + stm_nvic_set_priority(STM_ISR_USB_LP_POS, AO_STM_NVIC_LOW_PRIORITY); stm_nvic_set_enable(STM_ISR_USB_LP_POS); ao_usb_configuration = 0; -- cgit v1.2.3 From 839eadbc8e5694842eb498c6e47cfbf08ba8fbf4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 20 Nov 2016 02:59:40 -0800 Subject: altos/stm: Allow use basepri instead of primask for masking interrupts This allows for high priority interrupts (priority 0) to run, even when other interrupts are blocked. Code executing in such interrupt handlers must not attempt to control task execution as that will race with the scheduler. Select this by defining AO_NONMASK_INTERRUPT in ao_pins.h. non-maskable interrupt priority is AO_STM_NVIC_NONMASK_PRIORITY Signed-off-by: Keith Packard --- src/stm/ao_arch.h | 13 +++++--- src/stm/ao_arch_funcs.h | 84 ++++++++++++++++++++++++++++++++++++++++--------- src/stm/ao_usb_stm.c | 16 ++++++---- 3 files changed, 89 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/stm/ao_arch.h b/src/stm/ao_arch.h index 3d09af3c..5f033b66 100644 --- a/src/stm/ao_arch.h +++ b/src/stm/ao_arch.h @@ -85,10 +85,6 @@ extern const uint32_t ao_radio_cal; #define ao_arch_task_members\ uint32_t *sp; /* saved stack pointer */ -#define ao_arch_block_interrupts() asm("cpsid i") -#define ao_arch_release_interrupts() asm("cpsie i") - - /* * For now, we're running at a weird frequency */ @@ -124,6 +120,15 @@ extern const uint32_t ao_radio_cal; /* The stm32l implements only 4 bits of the priority fields */ +#if AO_NONMASK_INTERRUPT +#define AO_STM_NVIC_NONMASK_PRIORITY 0x00 + +/* Set the basepri register to this value to mask all + * non-maskable priorities + */ +#define AO_STM_NVIC_BASEPRI_MASK 0x10 +#endif + #define AO_STM_NVIC_HIGH_PRIORITY 0x40 #define AO_STM_NVIC_MED_PRIORITY 0x80 #define AO_STM_NVIC_LOW_PRIORITY 0xC0 diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index a9d0fa34..88097406 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -345,17 +345,43 @@ extern struct ao_stm_usart ao_stm_usart3; typedef uint32_t ao_arch_irq_t; +static inline void +ao_arch_block_interrupts(void) { +#ifdef AO_NONMASK_INTERRUPTS + asm("msr basepri,%0" : : "r" (AO_STM_NVIC_BASEPRI_MASK)); +#else + asm("cpsid i"); +#endif +} + +static inline void +ao_arch_release_interrupts(void) { +#ifdef AO_NONMASK_INTERRUPTS + asm("msr basepri,%0" : : "r" (0x0)); +#else + asm("cpsie i"); +#endif +} + static inline uint32_t ao_arch_irqsave(void) { - uint32_t primask; - asm("mrs %0,primask" : "=&r" (primask)); + uint32_t val; +#ifdef AO_NONMASK_INTERRUPTS + asm("mrs %0,basepri" : "=r" (val)); +#else + asm("mrs %0,primask" : "=r" (val)); +#endif ao_arch_block_interrupts(); - return primask; + return val; } static inline void -ao_arch_irqrestore(uint32_t primask) { - asm("msr primask,%0" : : "r" (primask)); +ao_arch_irqrestore(uint32_t basepri) { +#ifdef AO_NONMASK_INTERRUPTS + asm("msr basepri,%0" : : "r" (basepri)); +#else + asm("msr primask,%0" : : "r" (basepri)); +#endif } static inline void @@ -365,10 +391,17 @@ ao_arch_memory_barrier() { static inline void ao_arch_irq_check(void) { +#ifdef AO_NONMASK_INTERRUPTS + uint32_t basepri; + asm("mrs %0,basepri" : "=r" (basepri)); + if (basepri == 0) + ao_panic(AO_PANIC_IRQ); +#else uint32_t primask; - asm("mrs %0,primask" : "=&r" (primask)); + asm("mrs %0,primask" : "=r" (primask)); if ((primask & 1) == 0) ao_panic(AO_PANIC_IRQ); +#endif } #if HAS_TASK @@ -390,7 +423,7 @@ ao_arch_init_stack(struct ao_task *task, void *start) /* APSR */ ARM_PUSH32(sp, 0); - /* PRIMASK with interrupts enabled */ + /* BASEPRI with interrupts enabled */ ARM_PUSH32(sp, 0); task->sp = sp; @@ -404,8 +437,13 @@ static inline void ao_arch_save_regs(void) { asm("mrs r0,apsr"); asm("push {r0}"); +#ifdef AO_NONMASK_INTERRUPTS + /* Save BASEPRI */ + asm("mrs r0,basepri"); +#else /* Save PRIMASK */ asm("mrs r0,primask"); +#endif asm("push {r0}"); } @@ -419,9 +457,15 @@ static inline void ao_arch_restore_stack(void) { /* Switch stacks */ asm("mov sp, %0" : : "r" (ao_cur_task->sp) ); +#ifdef AO_NONMASK_INTERRUPTS + /* Restore BASEPRI */ + asm("pop {r0}"); + asm("msr basepri,r0"); +#else /* Restore PRIMASK */ asm("pop {r0}"); asm("msr primask,r0"); +#endif /* Restore APSR */ asm("pop {r0}"); @@ -463,7 +507,7 @@ static inline void ao_arch_start_scheduler(void) { asm("mrs %0,msp" : "=&r" (sp)); asm("msr psp,%0" : : "r" (sp)); - asm("mrs %0,control" : "=&r" (control)); + asm("mrs %0,control" : "=r" (control)); control |= (1 << 1); asm("msr control,%0" : : "r" (control)); asm("isb"); @@ -474,12 +518,24 @@ static inline void ao_arch_start_scheduler(void) { #endif -#define ao_arch_wait_interrupt() do { \ - asm("\twfi\n"); \ - ao_arch_release_interrupts(); \ - asm(".global ao_idle_loc\nao_idle_loc:"); \ - ao_arch_block_interrupts(); \ - } while (0) +static inline void +ao_arch_wait_interrupt(void) { +#ifdef AO_NONMASK_INTERRUPTS + asm( + "dsb\n" /* Serialize data */ + "isb\n" /* Serialize instructions */ + "cpsid i\n" /* Block all interrupts */ + "msr basepri,%0\n" /* Allow all interrupts through basepri */ + "wfi\n" /* Wait for an interrupt */ + "cpsie i\n" /* Allow all interrupts */ + "msr basepri,%1\n" /* Block interrupts through basepri */ + : : "r" (0), "r" (AO_STM_NVIC_BASEPRI_MASK)); +#else + asm("\twfi\n"); + ao_arch_release_interrupts(); + ao_arch_block_interrupts(); +#endif +} #define ao_arch_critical(b) do { \ uint32_t __mask = ao_arch_irqsave(); \ diff --git a/src/stm/ao_usb_stm.c b/src/stm/ao_usb_stm.c index 2abaf10f..33e0617c 100644 --- a/src/stm/ao_usb_stm.c +++ b/src/stm/ao_usb_stm.c @@ -1109,7 +1109,7 @@ struct ao_usb_dbg { int line; char *msg; uint32_t value; - uint32_t primask; + uint32_t prival; #if TX_DBG uint16_t in_count; uint32_t in_epr; @@ -1125,19 +1125,23 @@ struct ao_usb_dbg { #endif }; -#define NUM_USB_DBG 128 +#define NUM_USB_DBG 16 -static struct ao_usb_dbg dbg[128]; +static struct ao_usb_dbg dbg[NUM_USB_DBG]; static int dbg_i; static void _dbg(int line, char *msg, uint32_t value) { - uint32_t primask; + uint32_t prival; dbg[dbg_i].line = line; dbg[dbg_i].msg = msg; dbg[dbg_i].value = value; - asm("mrs %0,primask" : "=&r" (primask)); - dbg[dbg_i].primask = primask; +#if AO_NONMASK_INTERRUPT + asm("mrs %0,basepri" : "=&r" (prival)); +#else + asm("mrs %0,primask" : "=&r" (prival)); +#endif + dbg[dbg_i].prival = prival; #if TX_DBG dbg[dbg_i].in_count = in_count; dbg[dbg_i].in_epr = stm_usb.epr[AO_USB_IN_EPR]; -- cgit v1.2.3 From e6fb0f13ba230ad9ce86cfa7f56491a0a3bd4b3d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 10 Jan 2017 14:43:07 -0800 Subject: altos/avr: Avoid warning about unused args in stdio_put and stdio_get Signed-off-by: Keith Packard --- src/avr/ao_avr_stdio.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/avr/ao_avr_stdio.c b/src/avr/ao_avr_stdio.c index cca2a971..fde3c421 100644 --- a/src/avr/ao_avr_stdio.c +++ b/src/avr/ao_avr_stdio.c @@ -21,6 +21,7 @@ int stdio_put(char c, FILE *stream) { + (void) stream; putchar(c); return 0; } @@ -28,6 +29,7 @@ stdio_put(char c, FILE *stream) int stdio_get(FILE *stream) { + (void) stream; return (int) getchar() & 0xff; } -- cgit v1.2.3 From 5dc5e2e238f8c1a8ca35d85ec046124afa9385ad Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 10 Jan 2017 14:45:25 -0800 Subject: altos: Allow for console to be used for stdio Signed-off-by: Keith Packard --- src/kernel/ao_stdio.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/kernel/ao_stdio.c b/src/kernel/ao_stdio.c index b79d465a..f0ee0a14 100644 --- a/src/kernel/ao_stdio.c +++ b/src/kernel/ao_stdio.c @@ -55,6 +55,9 @@ #ifndef PACKET_HAS_SLAVE #define PACKET_HAS_SLAVE 0 #endif +#ifndef CONSOLE_STDIN +#define CONSOLE_STDIN 0 +#endif #define USE_SERIAL_STDIN (USE_SERIAL_0_STDIN + \ USE_SERIAL_1_STDIN + \ @@ -67,7 +70,7 @@ USE_SERIAL_8_STDIN + \ USE_SERIAL_9_STDIN) -#define AO_NUM_STDIOS (HAS_USB + PACKET_HAS_SLAVE + USE_SERIAL_STDIN) +#define AO_NUM_STDIOS (HAS_USB + PACKET_HAS_SLAVE + USE_SERIAL_STDIN + CONSOLE_STDIN) __xdata struct ao_stdio ao_stdios[AO_NUM_STDIOS]; -- cgit v1.2.3 From 72ea90d28817549c4343d2fea03a4c951f849cbe Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 20 Feb 2017 12:12:43 -0800 Subject: altos/stm: Allow DMA channels to be hijacked by other code This lets code which needs finer control over DMA to use the channel without interference, and leaves the DMA engine running so that it can. Signed-off-by: Keith Packard --- src/stm/ao_dma_stm.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/stm/ao_dma_stm.c b/src/stm/ao_dma_stm.c index 63d6688a..962b3acc 100644 --- a/src/stm/ao_dma_stm.c +++ b/src/stm/ao_dma_stm.c @@ -29,7 +29,6 @@ uint8_t ao_dma_done[NUM_DMA]; static struct ao_dma_config ao_dma_config[NUM_DMA]; static uint8_t ao_dma_allocated[NUM_DMA]; static uint8_t ao_dma_mutex[NUM_DMA]; -static uint8_t ao_dma_active; static void ao_dma_isr(uint8_t index) { @@ -49,12 +48,24 @@ ao_dma_isr(uint8_t index) { void stm_dma1_channel1_isr(void) { ao_dma_isr(STM_DMA_INDEX(1)); } void stm_dma1_channel2_isr(void) { ao_dma_isr(STM_DMA_INDEX(2)); } +#ifdef STM_DMA1_3_STOLEN +#define LEAVE_DMA_ON +#else void stm_dma1_channel3_isr(void) { ao_dma_isr(STM_DMA_INDEX(3)); } +#endif void stm_dma1_channel4_isr(void) { ao_dma_isr(STM_DMA_INDEX(4)); } +#ifdef STM_DMA1_5_STOLEN +#define LEAVE_DMA_ON +#else void stm_dma1_channel5_isr(void) { ao_dma_isr(STM_DMA_INDEX(5)); } +#endif void stm_dma1_channel6_isr(void) { ao_dma_isr(STM_DMA_INDEX(6)); } void stm_dma1_channel7_isr(void) { ao_dma_isr(STM_DMA_INDEX(7)); } +#ifndef LEAVE_DMA_ON +static uint8_t ao_dma_active; +#endif + void ao_dma_set_transfer(uint8_t index, volatile void *peripheral, @@ -68,10 +79,12 @@ ao_dma_set_transfer(uint8_t index, ao_dma_mutex[index] = 0xff; } else ao_mutex_get(&ao_dma_mutex[index]); +#ifndef LEAVE_DMA_ON ao_arch_critical( if (ao_dma_active++ == 0) stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMA1EN); ); +#endif stm_dma.channel[index].ccr = ccr | (1 << STM_DMA_CCR_TCIE); stm_dma.channel[index].cndtr = count; stm_dma.channel[index].cpar = peripheral; @@ -96,10 +109,12 @@ void ao_dma_done_transfer(uint8_t index) { stm_dma.channel[index].ccr &= ~(1 << STM_DMA_CCR_EN); +#ifndef LEAVE_DMA_ON ao_arch_critical( if (--ao_dma_active == 0) stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_DMA1EN); ); +#endif if (ao_dma_allocated[index]) ao_dma_mutex[index] = 0; else @@ -120,10 +135,12 @@ ao_dma_dump_cmd(void) { int i; +#ifndef LEAVE_DMA_ON ao_arch_critical( if (ao_dma_active++ == 0) stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMA1EN); ); +#endif printf ("isr %08x ifcr%08x\n", stm_dma.isr, stm_dma.ifcr); for (i = 0; i < NUM_DMA; i++) printf("%d: done %d allocated %d mutex %2d ccr %04x cndtr %04x cpar %08x cmar %08x isr %08x\n", @@ -136,10 +153,12 @@ ao_dma_dump_cmd(void) stm_dma.channel[i].cpar, stm_dma.channel[i].cmar, ao_dma_config[i].isr); +#ifndef LEAVE_DMA_ON ao_arch_critical( if (--ao_dma_active == 0) stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_DMA1EN); ); +#endif } static const struct ao_cmds ao_dma_cmds[] = { @@ -153,7 +172,24 @@ ao_dma_init(void) { int index; +#ifdef LEAVE_DMA_ON + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMA1EN); +#endif for (index = 0; index < STM_NUM_DMA; index++) { +#if STM_DMA1_5_STOLEN + if (index == STM_DMA_INDEX(5)) { + ao_dma_allocated[index] = 1; + ao_dma_mutex[index] = 0xff; + continue; + } +#endif +#if STM_DMA1_3_STOLEN + if (index == STM_DMA_INDEX(3)) { + ao_dma_allocated[index] = 1; + ao_dma_mutex[index] = 0xff; + continue; + } +#endif stm_nvic_set_enable(STM_ISR_DMA1_CHANNEL1_POS + index); stm_nvic_set_priority(STM_ISR_DMA1_CHANNEL1_POS + index, AO_STM_NVIC_MED_PRIORITY); -- cgit v1.2.3 From 80fd7f7bef5320ce86048d74dc4a72e1ec361120 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 20 Feb 2017 12:14:10 -0800 Subject: altos/stm: Make i2c code handle PCLK1 of 24MHz Just adds the necessary defines to the code. Signed-off-by: Keith Packard --- src/stm/ao_i2c_stm.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/stm/ao_i2c_stm.c b/src/stm/ao_i2c_stm.c index 29a8f173..59cad495 100644 --- a/src/stm/ao_i2c_stm.c +++ b/src/stm/ao_i2c_stm.c @@ -75,6 +75,9 @@ uint8_t ao_i2c_mutex[STM_NUM_I2C]; #if AO_PCLK1 == 16000000 # define AO_STM_I2C_CR2_FREQ STM_I2C_CR2_FREQ_16_MHZ #endif +#if AO_PCLK1 == 24000000 +# define AO_STM_I2C_CR2_FREQ STM_I2C_CR2_FREQ_24_MHZ +#endif #if AO_PCLK1 == 32000000 # define AO_STM_I2C_CR2_FREQ STM_I2C_CR2_FREQ_32_MHZ #endif -- cgit v1.2.3 From a487d2fcba57141f6b083d5612c76bac5ad1ac7c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 20 Feb 2017 12:15:45 -0800 Subject: altos/stm: Add nvic priority register fields. Add more TIM234 defines. Signed-off-by: Keith Packard --- src/stm/stm32l.h | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/stm/stm32l.h b/src/stm/stm32l.h index be1e1d65..a20efa8a 100644 --- a/src/stm/stm32l.h +++ b/src/stm/stm32l.h @@ -518,7 +518,7 @@ extern struct stm_rcc stm_rcc; #define STM_RCC_CFGR_MCOPRE_DIV_4 2 #define STM_RCC_CFGR_MCOPRE_DIV_8 3 #define STM_RCC_CFGR_MCOPRE_DIV_16 4 -#define STM_RCC_CFGR_MCOPRE_DIV_MASK 7 +#define STM_RCC_CFGR_MCOPRE_MASK 7 #define STM_RCC_CFGR_MCOSEL (24) #define STM_RCC_CFGR_MCOSEL_DISABLE 0 @@ -897,7 +897,11 @@ struct stm_nvic { vuint32_t sc; /* 0xc10 0xe000ed10 System Control Register */ vuint32_t cc; /* 0xc14 0xe000ed14 Configuration Control Register */ - uint8_t _unusedc18[0xe00 - 0xc18]; + vuint32_t shpr7_4; /* 0xc18 0xe000ed18 System Hander Priority Registers */ + vuint32_t shpr11_8; /* 0xc1c */ + vuint32_t shpr15_12; /* 0xc20 */ + + uint8_t _unusedc18[0xe00 - 0xc24]; vuint32_t stir; /* 0xe00 */ }; @@ -1594,6 +1598,7 @@ extern struct stm_i2c stm_i2c1, stm_i2c2; #define STM_I2C_CR2_FREQ_4_MHZ 4 #define STM_I2C_CR2_FREQ_8_MHZ 8 #define STM_I2C_CR2_FREQ_16_MHZ 16 +#define STM_I2C_CR2_FREQ_24_MHZ 24 #define STM_I2C_CR2_FREQ_32_MHZ 32 #define STM_I2C_CR2_FREQ_MASK 0x3f @@ -1740,6 +1745,12 @@ extern struct stm_tim234 stm_tim2, stm_tim3, stm_tim4; #define STM_TIM234_SMCR_SMS_EXTERNAL_CLOCK 7 #define STM_TIM234_SMCR_SMS_MASK 7 +#define STM_TIM234_DIER_CC4IE 4 +#define STM_TIM234_DIER_CC3IE 3 +#define STM_TIM234_DIER_CC2IE 2 +#define STM_TIM234_DIER_CC1IE 1 +#define STM_TIM234_DIER_UIE 0 + #define STM_TIM234_SR_CC4OF 12 #define STM_TIM234_SR_CC3OF 11 #define STM_TIM234_SR_CC2OF 10 @@ -1840,15 +1851,23 @@ extern struct stm_tim234 stm_tim2, stm_tim3, stm_tim4; #define STM_TIM234_CCER_CC4NP 15 #define STM_TIM234_CCER_CC4P 13 +#define STM_TIM234_CCER_CC4P_ACTIVE_HIGH 0 +#define STM_TIM234_CCER_CC4P_ACTIVE_LOW 1 #define STM_TIM234_CCER_CC4E 12 #define STM_TIM234_CCER_CC3NP 11 #define STM_TIM234_CCER_CC3P 9 +#define STM_TIM234_CCER_CC3P_ACTIVE_HIGH 0 +#define STM_TIM234_CCER_CC3P_ACTIVE_LOW 1 #define STM_TIM234_CCER_CC3E 8 #define STM_TIM234_CCER_CC2NP 7 #define STM_TIM234_CCER_CC2P 5 +#define STM_TIM234_CCER_CC2P_ACTIVE_HIGH 0 +#define STM_TIM234_CCER_CC2P_ACTIVE_LOW 1 #define STM_TIM234_CCER_CC2E 4 #define STM_TIM234_CCER_CC1NP 3 #define STM_TIM234_CCER_CC1P 1 +#define STM_TIM234_CCER_CC1P_ACTIVE_HIGH 0 +#define STM_TIM234_CCER_CC1P_ACTIVE_LOW 1 #define STM_TIM234_CCER_CC1E 0 struct stm_usb { -- cgit v1.2.3 From 1301d576d9bface4cc625e4a4187401f93f54444 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 20 Feb 2017 12:17:42 -0800 Subject: altos: Add bitmap drawing code Includes solid fills, text and lines. Signed-off-by: Keith Packard --- src/draw/5x7.bdf | 3190 ++++++++++++++++++++++++++++++++++++++++++++++++ src/draw/Makefile | 4 + src/draw/ao_blt.c | 294 +++++ src/draw/ao_copy.c | 75 ++ src/draw/ao_draw.h | 119 ++ src/draw/ao_draw_int.h | 136 +++ src/draw/ao_font.h | 139 +++ src/draw/ao_line.c | 314 +++++ src/draw/ao_pattern.c | 80 ++ src/draw/ao_rect.c | 46 + src/draw/ao_text.c | 65 + src/draw/font-convert | 150 +++ src/draw/line.5c | 389 ++++++ 13 files changed, 5001 insertions(+) create mode 100644 src/draw/5x7.bdf create mode 100644 src/draw/Makefile create mode 100644 src/draw/ao_blt.c create mode 100644 src/draw/ao_copy.c create mode 100644 src/draw/ao_draw.h create mode 100644 src/draw/ao_draw_int.h create mode 100644 src/draw/ao_font.h create mode 100644 src/draw/ao_line.c create mode 100644 src/draw/ao_pattern.c create mode 100644 src/draw/ao_rect.c create mode 100644 src/draw/ao_text.c create mode 100755 src/draw/font-convert create mode 100644 src/draw/line.5c (limited to 'src') diff --git a/src/draw/5x7.bdf b/src/draw/5x7.bdf new file mode 100644 index 00000000..b511f289 --- /dev/null +++ b/src/draw/5x7.bdf @@ -0,0 +1,3190 @@ +STARTFONT 2.1 +COMMENT Copyright 1991 Massachusetts Institute of Technology +COMMENT +COMMENT Permission to use, copy, modify, and distribute this software +COMMENT and its documentation for any purpose and without fee is +COMMENT hereby granted, provided that the above copyright notice +COMMENT appear in all copies and that both that copyright notice and +COMMENT this permission notice appear in supporting documentation, +COMMENT and that the name of M.I.T. not be used in advertising or +COMMENT publicity pertaining to distribution of the software without +COMMENT specific, written prior permission. M.I.T. makes no +COMMENT representations about the suitability of this software for +COMMENT any purpose. It is provided "as is" without express or +COMMENT implied warranty. +COMMENT +COMMENT M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +COMMENT INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +COMMENT FITNESS, IN NO EVENT SHALL M.I.T. BE LIABLE FOR ANY SPECIAL, +COMMENT INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER +COMMENT RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +COMMENT ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +COMMENT ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +COMMENT OF THIS SOFTWARE. +COMMENT +COMMENT Author: Stephen Gildea, MIT X Consortium, June 1991 +COMMENT +FONT -Misc-Fixed-Medium-R-Normal--7-70-75-75-C-50-ISO8859-1 +SIZE 7 75 75 +FONTBOUNDINGBOX 5 7 0 -1 +STARTPROPERTIES 21 +FONTNAME_REGISTRY "" +FOUNDRY "Misc" +FAMILY_NAME "Fixed" +WEIGHT_NAME "Medium" +SLANT "R" +SETWIDTH_NAME "Normal" +ADD_STYLE_NAME "" +PIXEL_SIZE 7 +POINT_SIZE 70 +RESOLUTION_X 75 +RESOLUTION_Y 75 +SPACING "C" +AVERAGE_WIDTH 50 +CHARSET_REGISTRY "ISO8859" +CHARSET_ENCODING "1" +FONT_ASCENT 6 +FONT_DESCENT 1 +UNDERLINE_POSITION 0 +DESTINATION 1 +DEFAULT_CHAR 0 +COPYRIGHT "Copyright 1991 Massachusetts Institute of Technology" +ENDPROPERTIES +CHARS 224 +STARTCHAR C000 +ENCODING 0 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +f0 +f0 +f0 +f0 +f0 +00 +ENDCHAR +STARTCHAR C001 +ENCODING 1 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +20 +70 +f8 +70 +20 +00 +ENDCHAR +STARTCHAR C002 +ENCODING 2 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +50 +a0 +50 +a0 +50 +a0 +00 +ENDCHAR +STARTCHAR C003 +ENCODING 3 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +a0 +e0 +a0 +a0 +70 +20 +20 +ENDCHAR +STARTCHAR C004 +ENCODING 4 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +c0 +80 +c0 +b0 +20 +30 +20 +ENDCHAR +STARTCHAR C005 +ENCODING 5 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +c0 +80 +c0 +60 +50 +60 +50 +ENDCHAR +STARTCHAR C006 +ENCODING 6 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +80 +80 +c0 +30 +20 +30 +20 +ENDCHAR +STARTCHAR C007 +ENCODING 7 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +50 +20 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C010 +ENCODING 8 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +70 +20 +00 +70 +00 +00 +ENDCHAR +STARTCHAR C011 +ENCODING 9 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +d0 +b0 +90 +20 +20 +30 +ENDCHAR +STARTCHAR C012 +ENCODING 10 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +a0 +a0 +a0 +40 +70 +20 +20 +ENDCHAR +STARTCHAR C013 +ENCODING 11 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +20 +20 +e0 +00 +00 +00 +ENDCHAR +STARTCHAR C014 +ENCODING 12 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +e0 +20 +20 +20 +ENDCHAR +STARTCHAR C015 +ENCODING 13 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +38 +20 +20 +20 +ENDCHAR +STARTCHAR C016 +ENCODING 14 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +20 +20 +38 +00 +00 +00 +ENDCHAR +STARTCHAR C017 +ENCODING 15 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +20 +20 +f8 +20 +20 +20 +ENDCHAR +STARTCHAR C020 +ENCODING 16 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +f8 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C021 +ENCODING 17 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 6 7 0 -1 +BITMAP +00 +00 +f8 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C022 +ENCODING 18 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +f8 +00 +00 +00 +ENDCHAR +STARTCHAR C023 +ENCODING 19 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +00 +f8 +00 +00 +ENDCHAR +STARTCHAR C024 +ENCODING 20 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +00 +00 +f8 +00 +ENDCHAR +STARTCHAR C025 +ENCODING 21 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +20 +20 +38 +20 +20 +20 +ENDCHAR +STARTCHAR C026 +ENCODING 22 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +20 +20 +e0 +20 +20 +20 +ENDCHAR +STARTCHAR C027 +ENCODING 23 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 6 7 0 -1 +BITMAP +20 +20 +20 +f8 +00 +00 +00 +ENDCHAR +STARTCHAR C030 +ENCODING 24 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +f8 +20 +20 +20 +ENDCHAR +STARTCHAR C031 +ENCODING 25 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +20 +20 +20 +20 +20 +20 +ENDCHAR +STARTCHAR C032 +ENCODING 26 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +10 +20 +40 +20 +10 +70 +00 +ENDCHAR +STARTCHAR C033 +ENCODING 27 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +20 +10 +20 +40 +70 +00 +ENDCHAR +STARTCHAR C034 +ENCODING 28 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +70 +50 +50 +50 +00 +ENDCHAR +STARTCHAR C035 +ENCODING 29 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +10 +70 +20 +70 +40 +00 +ENDCHAR +STARTCHAR C036 +ENCODING 30 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +30 +40 +e0 +40 +b0 +00 +ENDCHAR +STARTCHAR C037 +ENCODING 31 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +20 +00 +00 +00 +ENDCHAR +STARTCHAR C040 +ENCODING 32 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR ! +ENCODING 33 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +20 +20 +20 +00 +20 +00 +ENDCHAR +STARTCHAR " +ENCODING 34 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +50 +50 +50 +00 +00 +00 +00 +ENDCHAR +STARTCHAR # +ENCODING 35 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +50 +f8 +50 +f8 +50 +00 +ENDCHAR +STARTCHAR $ +ENCODING 36 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +70 +a0 +70 +28 +70 +00 +ENDCHAR +STARTCHAR % +ENCODING 37 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +80 +90 +20 +40 +90 +10 +00 +ENDCHAR +STARTCHAR & +ENCODING 38 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +40 +a0 +40 +a0 +50 +00 +ENDCHAR +STARTCHAR ' +ENCODING 39 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +40 +80 +00 +00 +00 +00 +ENDCHAR +STARTCHAR ( +ENCODING 40 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +40 +40 +40 +40 +20 +00 +ENDCHAR +STARTCHAR ) +ENCODING 41 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +20 +20 +20 +20 +40 +00 +ENDCHAR +STARTCHAR * +ENCODING 42 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +a0 +40 +e0 +40 +a0 +00 +ENDCHAR +STARTCHAR + +ENCODING 43 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +20 +20 +f8 +20 +20 +00 +ENDCHAR +STARTCHAR , +ENCODING 44 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +00 +60 +40 +80 +ENDCHAR +STARTCHAR - +ENCODING 45 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +f0 +00 +00 +00 +ENDCHAR +STARTCHAR . +ENCODING 46 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +00 +60 +60 +00 +ENDCHAR +STARTCHAR / +ENCODING 47 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +10 +20 +40 +80 +00 +00 +ENDCHAR +STARTCHAR 0 +ENCODING 48 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +a0 +a0 +a0 +a0 +40 +00 +ENDCHAR +STARTCHAR 1 +ENCODING 49 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +c0 +40 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR 2 +ENCODING 50 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +10 +20 +40 +f0 +00 +ENDCHAR +STARTCHAR 3 +ENCODING 51 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +10 +60 +10 +90 +60 +00 +ENDCHAR +STARTCHAR 4 +ENCODING 52 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +60 +a0 +f0 +20 +20 +00 +ENDCHAR +STARTCHAR 5 +ENCODING 53 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +80 +e0 +10 +90 +60 +00 +ENDCHAR +STARTCHAR 6 +ENCODING 54 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +80 +e0 +90 +90 +60 +00 +ENDCHAR +STARTCHAR 7 +ENCODING 55 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +10 +20 +20 +40 +40 +00 +ENDCHAR +STARTCHAR 8 +ENCODING 56 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +60 +90 +90 +60 +00 +ENDCHAR +STARTCHAR 9 +ENCODING 57 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +70 +10 +60 +00 +ENDCHAR +STARTCHAR : +ENCODING 58 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +60 +60 +00 +60 +60 +00 +ENDCHAR +STARTCHAR ; +ENCODING 59 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +60 +60 +00 +60 +40 +80 +ENDCHAR +STARTCHAR < +ENCODING 60 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +20 +40 +80 +40 +20 +00 +ENDCHAR +STARTCHAR = +ENCODING 61 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +f0 +00 +f0 +00 +00 +ENDCHAR +STARTCHAR > +ENCODING 62 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +80 +40 +20 +40 +80 +00 +ENDCHAR +STARTCHAR ? +ENCODING 63 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +a0 +20 +40 +00 +40 +00 +ENDCHAR +STARTCHAR @ +ENCODING 64 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +b0 +b0 +80 +60 +00 +ENDCHAR +STARTCHAR A +ENCODING 65 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +f0 +90 +90 +00 +ENDCHAR +STARTCHAR B +ENCODING 66 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +90 +e0 +90 +90 +e0 +00 +ENDCHAR +STARTCHAR C +ENCODING 67 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +80 +80 +90 +60 +00 +ENDCHAR +STARTCHAR D +ENCODING 68 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +90 +90 +90 +90 +e0 +00 +ENDCHAR +STARTCHAR E +ENCODING 69 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +80 +e0 +80 +80 +f0 +00 +ENDCHAR +STARTCHAR F +ENCODING 70 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +80 +e0 +80 +80 +80 +00 +ENDCHAR +STARTCHAR G +ENCODING 71 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +80 +b0 +90 +70 +00 +ENDCHAR +STARTCHAR H +ENCODING 72 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +90 +f0 +90 +90 +90 +00 +ENDCHAR +STARTCHAR I +ENCODING 73 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +40 +40 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR J +ENCODING 74 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +10 +10 +10 +10 +90 +60 +00 +ENDCHAR +STARTCHAR K +ENCODING 75 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +a0 +c0 +c0 +a0 +90 +00 +ENDCHAR +STARTCHAR L +ENCODING 76 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +80 +80 +80 +80 +80 +f0 +00 +ENDCHAR +STARTCHAR M +ENCODING 77 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +f0 +f0 +90 +90 +90 +00 +ENDCHAR +STARTCHAR N +ENCODING 78 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +d0 +d0 +b0 +b0 +90 +00 +ENDCHAR +STARTCHAR O +ENCODING 79 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR P +ENCODING 80 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +90 +90 +e0 +80 +80 +00 +ENDCHAR +STARTCHAR Q +ENCODING 81 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +90 +d0 +60 +10 +ENDCHAR +STARTCHAR R +ENCODING 82 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +90 +90 +e0 +a0 +90 +00 +ENDCHAR +STARTCHAR S +ENCODING 83 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +40 +20 +90 +60 +00 +ENDCHAR +STARTCHAR T +ENCODING 84 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +40 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR U +ENCODING 85 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR V +ENCODING 86 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +90 +90 +90 +60 +60 +00 +ENDCHAR +STARTCHAR W +ENCODING 87 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +90 +90 +f0 +f0 +90 +00 +ENDCHAR +STARTCHAR X +ENCODING 88 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +90 +60 +60 +90 +90 +00 +ENDCHAR +STARTCHAR Y +ENCODING 89 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +a0 +a0 +a0 +40 +40 +40 +00 +ENDCHAR +STARTCHAR Z +ENCODING 90 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +10 +20 +40 +80 +f0 +00 +ENDCHAR +STARTCHAR [ +ENCODING 91 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +80 +80 +80 +80 +e0 +00 +ENDCHAR +STARTCHAR \ +ENCODING 92 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +80 +40 +20 +10 +00 +00 +ENDCHAR +STARTCHAR ] +ENCODING 93 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +20 +20 +20 +20 +e0 +00 +ENDCHAR +STARTCHAR ^ +ENCODING 94 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +a0 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR _ +ENCODING 95 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +00 +00 +f0 +00 +ENDCHAR +STARTCHAR ` +ENCODING 96 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +c0 +40 +20 +00 +00 +00 +00 +ENDCHAR +STARTCHAR a +ENCODING 97 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +70 +90 +b0 +50 +00 +ENDCHAR +STARTCHAR b +ENCODING 98 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +80 +80 +e0 +90 +90 +e0 +00 +ENDCHAR +STARTCHAR c +ENCODING 99 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +60 +80 +80 +60 +00 +ENDCHAR +STARTCHAR d +ENCODING 100 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +10 +10 +70 +90 +90 +70 +00 +ENDCHAR +STARTCHAR e +ENCODING 101 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +60 +b0 +c0 +60 +00 +ENDCHAR +STARTCHAR f +ENCODING 102 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +50 +40 +e0 +40 +40 +00 +ENDCHAR +STARTCHAR g +ENCODING 103 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +70 +90 +60 +80 +70 +ENDCHAR +STARTCHAR h +ENCODING 104 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +80 +80 +e0 +90 +90 +90 +00 +ENDCHAR +STARTCHAR i +ENCODING 105 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +00 +c0 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR j +ENCODING 106 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +00 +20 +20 +20 +a0 +40 +ENDCHAR +STARTCHAR k +ENCODING 107 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +80 +80 +a0 +c0 +a0 +90 +00 +ENDCHAR +STARTCHAR l +ENCODING 108 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +c0 +40 +40 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR m +ENCODING 109 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +a0 +f0 +90 +90 +00 +ENDCHAR +STARTCHAR n +ENCODING 110 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +e0 +90 +90 +90 +00 +ENDCHAR +STARTCHAR o +ENCODING 111 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +60 +90 +90 +60 +00 +ENDCHAR +STARTCHAR p +ENCODING 112 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +e0 +90 +90 +e0 +80 +ENDCHAR +STARTCHAR q +ENCODING 113 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +70 +90 +90 +70 +10 +ENDCHAR +STARTCHAR r +ENCODING 114 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +e0 +90 +80 +80 +00 +ENDCHAR +STARTCHAR s +ENCODING 115 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 6 7 0 -1 +BITMAP +00 +00 +70 +c0 +30 +e0 +00 +ENDCHAR +STARTCHAR t +ENCODING 116 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +40 +e0 +40 +40 +30 +00 +ENDCHAR +STARTCHAR u +ENCODING 117 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +90 +90 +90 +70 +00 +ENDCHAR +STARTCHAR v +ENCODING 118 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +a0 +a0 +a0 +40 +00 +ENDCHAR +STARTCHAR w +ENCODING 119 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +90 +90 +f0 +f0 +00 +ENDCHAR +STARTCHAR x +ENCODING 120 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +90 +60 +60 +90 +00 +ENDCHAR +STARTCHAR y +ENCODING 121 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +90 +90 +50 +20 +40 +ENDCHAR +STARTCHAR z +ENCODING 122 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +f0 +20 +40 +f0 +00 +ENDCHAR +STARTCHAR { +ENCODING 123 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +40 +c0 +40 +40 +20 +00 +ENDCHAR +STARTCHAR | +ENCODING 124 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +40 +40 +40 +40 +40 +00 +ENDCHAR +STARTCHAR } +ENCODING 125 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 6 7 0 -1 +BITMAP +80 +40 +60 +40 +40 +80 +00 +ENDCHAR +STARTCHAR ~ +ENCODING 126 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +50 +a0 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR Blank +ENCODING 127 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C160 +ENCODING 160 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C161 +ENCODING 161 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +00 +20 +20 +20 +20 +00 +ENDCHAR +STARTCHAR C162 +ENCODING 162 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +20 +70 +a0 +a0 +70 +20 +ENDCHAR +STARTCHAR C163 +ENCODING 163 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +30 +40 +e0 +40 +b0 +00 +ENDCHAR +STARTCHAR C164 +ENCODING 164 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +88 +70 +50 +70 +88 +00 +ENDCHAR +STARTCHAR C165 +ENCODING 165 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +a0 +a0 +40 +e0 +40 +40 +00 +ENDCHAR +STARTCHAR C166 +ENCODING 166 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +20 +20 +00 +20 +20 +00 +ENDCHAR +STARTCHAR C167 +ENCODING 167 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +30 +40 +60 +50 +30 +10 +60 +ENDCHAR +STARTCHAR C168 +ENCODING 168 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +50 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C169 +ENCODING 169 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +70 +88 +a8 +c8 +a8 +88 +70 +ENDCHAR +STARTCHAR C170 +ENCODING 170 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +a0 +60 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C171 +ENCODING 171 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +48 +90 +48 +00 +00 +ENDCHAR +STARTCHAR C172 +ENCODING 172 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +f0 +10 +00 +00 +00 +ENDCHAR +STARTCHAR C173 +ENCODING 173 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +f0 +00 +00 +00 +ENDCHAR +STARTCHAR C174 +ENCODING 174 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +70 +88 +e8 +c8 +c8 +88 +70 +ENDCHAR +STARTCHAR C175 +ENCODING 175 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +00 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C176 +ENCODING 176 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +50 +20 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C177 +ENCODING 177 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +20 +f8 +20 +20 +f8 +00 +ENDCHAR +STARTCHAR C178 +ENCODING 178 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +20 +40 +60 +00 +00 +00 +ENDCHAR +STARTCHAR C179 +ENCODING 179 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +60 +20 +60 +00 +00 +00 +ENDCHAR +STARTCHAR C180 +ENCODING 180 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +40 +00 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C181 +ENCODING 181 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +90 +90 +90 +e0 +80 +ENDCHAR +STARTCHAR C182 +ENCODING 182 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +70 +d0 +d0 +50 +50 +50 +00 +ENDCHAR +STARTCHAR C183 +ENCODING 183 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +60 +60 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C184 +ENCODING 184 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +00 +00 +00 +20 +40 +ENDCHAR +STARTCHAR C185 +ENCODING 185 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +60 +20 +70 +00 +00 +00 +ENDCHAR +STARTCHAR C186 +ENCODING 186 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +a0 +40 +00 +00 +00 +00 +ENDCHAR +STARTCHAR C187 +ENCODING 187 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +90 +48 +90 +00 +00 +ENDCHAR +STARTCHAR C188 +ENCODING 188 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +80 +80 +80 +90 +30 +70 +10 +ENDCHAR +STARTCHAR C189 +ENCODING 189 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +80 +80 +80 +b0 +10 +20 +30 +ENDCHAR +STARTCHAR C190 +ENCODING 190 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +c0 +c0 +40 +d0 +30 +70 +10 +ENDCHAR +STARTCHAR C191 +ENCODING 191 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +00 +40 +80 +a0 +40 +00 +ENDCHAR +STARTCHAR Agrave +ENCODING 192 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +f0 +90 +90 +00 +ENDCHAR +STARTCHAR C193 +ENCODING 193 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +f0 +90 +90 +00 +ENDCHAR +STARTCHAR C194 +ENCODING 194 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +f0 +90 +90 +00 +ENDCHAR +STARTCHAR C195 +ENCODING 195 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +f0 +90 +90 +00 +ENDCHAR +STARTCHAR C196 +ENCODING 196 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +f0 +90 +90 +00 +ENDCHAR +STARTCHAR C197 +ENCODING 197 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +f0 +90 +90 +00 +ENDCHAR +STARTCHAR C198 +ENCODING 198 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +70 +a0 +b0 +e0 +a0 +b0 +00 +ENDCHAR +STARTCHAR C199 +ENCODING 199 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +80 +80 +90 +60 +40 +ENDCHAR +STARTCHAR Egrave +ENCODING 200 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +80 +e0 +80 +80 +f0 +00 +ENDCHAR +STARTCHAR C201 +ENCODING 201 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +80 +e0 +80 +80 +f0 +00 +ENDCHAR +STARTCHAR C202 +ENCODING 202 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +80 +e0 +80 +80 +f0 +00 +ENDCHAR +STARTCHAR C203 +ENCODING 203 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +f0 +80 +e0 +80 +80 +f0 +00 +ENDCHAR +STARTCHAR C204 +ENCODING 204 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +40 +40 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR C205 +ENCODING 205 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +40 +40 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR C206 +ENCODING 206 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +40 +40 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR C207 +ENCODING 207 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +40 +40 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR C208 +ENCODING 208 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +e0 +50 +d0 +50 +50 +e0 +00 +ENDCHAR +STARTCHAR C209 +ENCODING 209 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +b0 +90 +d0 +b0 +b0 +90 +00 +ENDCHAR +STARTCHAR Ograve +ENCODING 210 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C211 +ENCODING 211 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C212 +ENCODING 212 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C213 +ENCODING 213 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C214 +ENCODING 214 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C215 +ENCODING 215 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +90 +60 +60 +90 +00 +ENDCHAR +STARTCHAR C216 +ENCODING 216 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +70 +b0 +b0 +d0 +d0 +e0 +00 +ENDCHAR +STARTCHAR Ugrave +ENCODING 217 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C218 +ENCODING 218 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C219 +ENCODING 219 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C220 +ENCODING 220 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +90 +90 +90 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C221 +ENCODING 221 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +a0 +a0 +a0 +40 +40 +40 +00 +ENDCHAR +STARTCHAR C222 +ENCODING 222 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +80 +e0 +90 +e0 +80 +80 +00 +ENDCHAR +STARTCHAR C223 +ENCODING 223 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +90 +e0 +90 +d0 +a0 +80 +ENDCHAR +STARTCHAR a-grave +ENCODING 224 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +20 +70 +90 +b0 +50 +00 +ENDCHAR +STARTCHAR C225 +ENCODING 225 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +40 +70 +90 +b0 +50 +00 +ENDCHAR +STARTCHAR C226 +ENCODING 226 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +50 +70 +90 +b0 +50 +00 +ENDCHAR +STARTCHAR C227 +ENCODING 227 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +50 +a0 +70 +90 +b0 +50 +00 +ENDCHAR +STARTCHAR C228 +ENCODING 228 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +50 +00 +70 +90 +b0 +50 +00 +ENDCHAR +STARTCHAR C229 +ENCODING 229 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +60 +70 +90 +b0 +50 +00 +ENDCHAR +STARTCHAR C230 +ENCODING 230 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +70 +b0 +a0 +70 +00 +ENDCHAR +STARTCHAR C231 +ENCODING 231 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +60 +80 +80 +60 +40 +ENDCHAR +STARTCHAR e-grave +ENCODING 232 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +20 +60 +b0 +c0 +60 +00 +ENDCHAR +STARTCHAR C233 +ENCODING 233 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +40 +60 +b0 +c0 +60 +00 +ENDCHAR +STARTCHAR C234 +ENCODING 234 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +a0 +60 +b0 +c0 +60 +00 +ENDCHAR +STARTCHAR C235 +ENCODING 235 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +a0 +00 +60 +b0 +c0 +60 +00 +ENDCHAR +STARTCHAR C236 +ENCODING 236 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +80 +40 +c0 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR C237 +ENCODING 237 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +80 +c0 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR C238 +ENCODING 238 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +a0 +c0 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR C239 +ENCODING 239 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +a0 +00 +c0 +40 +40 +e0 +00 +ENDCHAR +STARTCHAR C240 +ENCODING 240 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +30 +60 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C241 +ENCODING 241 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +50 +a0 +e0 +90 +90 +90 +00 +ENDCHAR +STARTCHAR C242 +ENCODING 242 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +20 +60 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C243 +ENCODING 243 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +40 +60 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C244 +ENCODING 244 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +00 +60 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C245 +ENCODING 245 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +50 +a0 +60 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C246 +ENCODING 246 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +a0 +00 +60 +90 +90 +60 +00 +ENDCHAR +STARTCHAR C247 +ENCODING 247 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +60 +00 +f0 +00 +60 +00 +ENDCHAR +STARTCHAR C248 +ENCODING 248 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +00 +70 +b0 +d0 +e0 +00 +ENDCHAR +STARTCHAR C249 +ENCODING 249 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +40 +20 +90 +90 +90 +70 +00 +ENDCHAR +STARTCHAR C250 +ENCODING 250 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +40 +90 +90 +90 +70 +00 +ENDCHAR +STARTCHAR C251 +ENCODING 251 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +60 +00 +90 +90 +90 +70 +00 +ENDCHAR +STARTCHAR C252 +ENCODING 252 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +50 +00 +90 +90 +90 +70 +00 +ENDCHAR +STARTCHAR C253 +ENCODING 253 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +20 +40 +90 +90 +50 +20 +40 +ENDCHAR +STARTCHAR C254 +ENCODING 254 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +00 +80 +e0 +90 +90 +e0 +80 +ENDCHAR +STARTCHAR C255 +ENCODING 255 +SWIDTH 686 0 +DWIDTH 5 0 +BBX 5 7 0 -1 +BITMAP +50 +00 +90 +90 +50 +20 +40 +ENDCHAR +ENDFONT diff --git a/src/draw/Makefile b/src/draw/Makefile new file mode 100644 index 00000000..0a542a1f --- /dev/null +++ b/src/draw/Makefile @@ -0,0 +1,4 @@ +BDF=5x7.bdf + +ao_font.h: font-convert $(BDF) + nickle font-convert $(BDF) > $@ diff --git a/src/draw/ao_blt.c b/src/draw/ao_blt.c new file mode 100644 index 00000000..e3f45221 --- /dev/null +++ b/src/draw/ao_blt.c @@ -0,0 +1,294 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao.h" +#include "ao_draw.h" +#include "ao_draw_int.h" + +#define O 0 +#define I AO_ALLONES + +struct ao_merge_rop { + uint32_t ca1, cx1, ca2, cx2; +}; + +const struct ao_merge_rop ao_merge_rop[16] = { + {O, O, O, O}, /* clear 0x0 0 */ + {I, O, O, O}, /* and 0x1 src AND dst */ + {I, O, I, O}, /* andReverse 0x2 src AND NOT dst */ + {O, O, I, O}, /* copy 0x3 src */ + {I, I, O, O}, /* andInverted 0x4 NOT src AND dst */ + {O, I, O, O}, /* noop 0x5 dst */ + {O, I, I, O}, /* xor 0x6 src XOR dst */ + {I, I, I, O}, /* or 0x7 src OR dst */ + {I, I, I, I}, /* nor 0x8 NOT src AND NOT dst */ + {O, I, I, I}, /* equiv 0x9 NOT src XOR dst */ + {O, I, O, I}, /* invert 0xa NOT dst */ + {I, I, O, I}, /* orReverse 0xb src OR NOT dst */ + {O, O, I, I}, /* copyInverted 0xc NOT src */ + {I, O, I, I}, /* orInverted 0xd NOT src OR dst */ + {I, O, O, I}, /* nand 0xe NOT src OR NOT dst */ + {O, O, O, I}, /* set 0xf 1 */ +}; + +#define ao_do_merge_rop(src, dst) \ + (((dst) & (((src) & _ca1) ^ _cx1)) ^ (((src) & _ca2) ^ _cx2)) + +#define ao_do_dst_invarient_merge_rop(src) (((src) & _ca2) ^ _cx2) + +#define ao_do_mask_merge_rop(src, dst, mask) \ + (((dst) & ((((src) & _ca1) ^ _cx1) | ~(mask))) ^ ((((src) & _ca2) ^ _cx2) & (mask))) + +#define ao_dst_invarient_merge_rop() (_ca1 == 0 && _cx1 == 0) + +void +ao_blt(uint32_t *src_line, + int16_t src_stride, + int16_t src_x, + uint32_t *dst_line, + int16_t dst_stride, + int16_t dst_x, + int16_t width, + int16_t height, + uint8_t rop, + uint8_t reverse, + uint8_t upsidedown) +{ + uint32_t *src, *dst; + uint32_t _ca1, _cx1, _ca2, _cx2; + uint8_t dst_invarient; + uint32_t startmask, endmask; + int16_t nmiddle, n; + uint32_t bits1, bits; + int16_t left_shift, right_shift; + + _ca1 = ao_merge_rop[rop].ca1; + _cx1 = ao_merge_rop[rop].cx1; + _ca2 = ao_merge_rop[rop].ca2; + _cx2 = ao_merge_rop[rop].cx2; + dst_invarient = ao_dst_invarient_merge_rop(); + + if (upsidedown) { + src_line += (height - 1) * src_stride; + dst_line += (height - 1) * dst_stride; + src_stride = -src_stride; + dst_stride = -dst_stride; + } + + ao_mask_bits(dst_x, width, startmask, nmiddle, endmask); + if (reverse) { + src_line += ((src_x + width - 1) >> AO_SHIFT) + 1; + dst_line += ((dst_x + width - 1) >> AO_SHIFT) + 1; + src_x = (src_x + width - 1) & AO_MASK; + dst_x = (dst_x + width - 1) & AO_MASK; + } else { + src_line += src_x >> AO_SHIFT; + dst_line += dst_x >> AO_SHIFT; + src_x &= AO_MASK; + dst_x &= AO_MASK; + } + if (src_x == dst_x) { + while (height--) { + src = src_line; + src_line += src_stride; + dst = dst_line; + dst_line += dst_stride; + if (reverse) { + if (endmask) { + bits = *--src; + --dst; + *dst = ao_do_mask_merge_rop(bits, *dst, endmask); + } + n = nmiddle; + if (dst_invarient) { + while (n--) + *--dst = ao_do_dst_invarient_merge_rop(*--src); + } + else { + while (n--) { + bits = *--src; + --dst; + *dst = ao_do_merge_rop(bits, *dst); + } + } + if (startmask) { + bits = *--src; + --dst; + *dst = ao_do_mask_merge_rop(bits, *dst, startmask); + } + } + else { + if (startmask) { + bits = *src++; + *dst = ao_do_mask_merge_rop(bits, *dst, startmask); + dst++; + } + n = nmiddle; + if (dst_invarient) { + while (n--) + *dst++ = ao_do_dst_invarient_merge_rop(*src++); + } + else { + while (n--) { + bits = *src++; + *dst = ao_do_merge_rop(bits, *dst); + dst++; + } + } + if (endmask) { + bits = *src; + *dst = ao_do_mask_merge_rop(bits, *dst, endmask); + } + } + } + } else { + if (src_x > dst_x) { + left_shift = src_x - dst_x; + right_shift = AO_UNIT - left_shift; + } else { + right_shift = dst_x - src_x; + left_shift = AO_UNIT - right_shift; + } + while (height--) { + src = src_line; + src_line += src_stride; + dst = dst_line; + dst_line += dst_stride; + + bits1 = 0; + if (reverse) { + if (src_x < dst_x) + bits1 = *--src; + if (endmask) { + bits = ao_right(bits1, right_shift); + if (ao_right(endmask, left_shift)) { + bits1 = *--src; + bits |= ao_left(bits1, left_shift); + } + --dst; + *dst = ao_do_mask_merge_rop(bits, *dst, endmask); + } + n = nmiddle; + if (dst_invarient) { + while (n--) { + bits = ao_right(bits1, right_shift); + bits1 = *--src; + bits |= ao_left(bits1, left_shift); + --dst; + *dst = ao_do_dst_invarient_merge_rop(bits); + } + } else { + while (n--) { + bits = ao_right(bits1, right_shift); + bits1 = *--src; + bits |= ao_left(bits1, left_shift); + --dst; + *dst = ao_do_merge_rop(bits, *dst); + } + } + if (startmask) { + bits = ao_right(bits1, right_shift); + if (ao_right(startmask, left_shift)) { + bits1 = *--src; + bits |= ao_left(bits1, left_shift); + } + --dst; + *dst = ao_do_mask_merge_rop(bits, *dst, startmask); + } + } + else { + if (src_x > dst_x) + bits1 = *src++; + if (startmask) { + bits = ao_left(bits1, left_shift); + if (ao_left(startmask, right_shift)) { + bits1 = *src++; + bits |= ao_right(bits1, right_shift); + } + *dst = ao_do_mask_merge_rop(bits, *dst, startmask); + dst++; + } + n = nmiddle; + if (dst_invarient) { + while (n--) { + bits = ao_left(bits1, left_shift); + bits1 = *src++; + bits |= ao_right(bits1, right_shift); + *dst = ao_do_dst_invarient_merge_rop(bits); + dst++; + } + } + else { + while (n--) { + bits = ao_left(bits1, left_shift); + bits1 = *src++; + bits |= ao_right(bits1, right_shift); + *dst = ao_do_merge_rop(bits, *dst); + dst++; + } + } + if (endmask) { + bits = ao_left(bits1, left_shift); + if (ao_left(endmask, right_shift)) { + bits1 = *src; + bits |= ao_right(bits1, right_shift); + } + *dst = ao_do_mask_merge_rop(bits, *dst, endmask); + } + } + } + } +} + +void +ao_solid(uint32_t and, + uint32_t xor, + uint32_t *dst, + int16_t dst_stride, + int16_t dst_x, + int16_t width, + int16_t height) +{ + uint32_t startmask, endmask; + int16_t nmiddle; + int16_t n; + + dst += dst_x >> AO_SHIFT; + dst_x &= AO_MASK; + + ao_mask_bits(dst_x, width, startmask, nmiddle, endmask); + + if (startmask) + dst_stride--; + + dst_stride -= nmiddle; + while (height--) { + if (startmask) { + *dst = ao_do_mask_rrop(*dst, and, xor, startmask); + dst++; + } + n = nmiddle; + if (!and) + while (n--) + *dst++ = xor; + else + while (n--) { + *dst = ao_do_rrop(*dst, and, xor); + dst++; + } + if (endmask) + *dst = ao_do_mask_rrop(*dst, and, xor, endmask); + dst += dst_stride; + } +} diff --git a/src/draw/ao_copy.c b/src/draw/ao_copy.c new file mode 100644 index 00000000..47067bb8 --- /dev/null +++ b/src/draw/ao_copy.c @@ -0,0 +1,75 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao.h" +#include "ao_draw.h" +#include "ao_draw_int.h" + +#define bound(val,max,other) do { \ + if (val < 0) { \ + other -= val; \ + val = 0; \ + } \ + if (val > max) { \ + other -= (val - max); \ + val = max; \ + } \ + } while (0) + +#define bound2(a, max_a, b, max_b) do { \ + bound(a, max_a, b); \ + bound(b, max_b, a); \ + } while (0) + +void +ao_copy(const struct ao_bitmap *dst, + int16_t dst_x, + int16_t dst_y, + int16_t width, + int16_t height, + const struct ao_bitmap *src, + int16_t src_x, + int16_t src_y, + uint8_t rop) +{ + int16_t dst_x2 = dst_x + width, dst_y2 = dst_y + height; + int16_t src_x2 = src_x + width, src_y2 = src_y + height; + uint8_t reverse = 0; + uint8_t upsidedown = 0; + + bound2(dst_x, dst->width, src_x, src->width); + bound2(dst_x2, dst->width, src_x2, src->width); + bound2(dst_y, dst->height, src_y, src->height); + bound2(dst_y2, dst->height, src_y2, src->height); + + if (dst == src) { + reverse = (dst_x > src_x); + upsidedown = (dst_y > src_y); + } + + if (dst_x < dst_x2 && dst_y < dst_y2) { + ao_blt(src->base + src_y * src->stride, + src->stride, + src_x, + dst->base + dst_y * dst->stride, + dst->stride, + dst_x, + dst_x2 - dst_x, + dst_y2 - dst_y, + rop, + reverse, + upsidedown); + } +} + diff --git a/src/draw/ao_draw.h b/src/draw/ao_draw.h new file mode 100644 index 00000000..92150fc1 --- /dev/null +++ b/src/draw/ao_draw.h @@ -0,0 +1,119 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _AO_DRAW_H_ +#define _AO_DRAW_H_ + +struct ao_bitmap { + uint32_t *base; + int16_t stride; /* in units */ + int16_t width; /* in pixels */ + int16_t height; /* in pixels */ +}; + +struct ao_pattern { + uint8_t pattern[8]; +}; + +void +ao_copy(const struct ao_bitmap *dst, + int16_t dst_x, + int16_t dst_y, + int16_t width, + int16_t height, + const struct ao_bitmap *src, + int16_t src_x, + int16_t src_y, + uint8_t rop); + +void +ao_rect(const struct ao_bitmap *dst, + int16_t x, + int16_t y, + int16_t width, + int16_t height, + uint32_t fill, + uint8_t rop); + +void +ao_pattern(const struct ao_bitmap *dst, + int16_t x, + int16_t y, + int16_t width, + int16_t height, + const struct ao_pattern *pattern, + int16_t pat_x, + int16_t pat_y, + uint8_t rop); + +void +ao_line(const struct ao_bitmap *dst, + int16_t x1, + int16_t y1, + int16_t x2, + int16_t y2, + uint32_t fill, + uint8_t rop); + +void +ao_text(const struct ao_bitmap *dst, + int16_t x, + int16_t y, + char *string, + uint32_t fill, + uint8_t rop); + +struct ao_font { + int width; + int height; + int ascent; + int descent; +}; + +extern const struct ao_font ao_font; + +#define AO_SHIFT 5 +#define AO_UNIT (1 << AO_SHIFT) +#define AO_MASK (AO_UNIT - 1) +#define AO_ALLONES ((uint32_t) -1) + +/* + * dst + * 0 1 + * + * 0 a b + * src + * 1 c d + * + * ROP = abcd + */ + +#define AO_CLEAR 0x0 /* 0 */ +#define AO_AND 0x1 /* src AND dst */ +#define AO_AND_REVERSE 0x2 /* src AND NOT dst */ +#define AO_COPY 0x3 /* src */ +#define AO_AND_INVERTED 0x4 /* NOT src AND dst */ +#define AO_NOOP 0x5 /* dst */ +#define AO_XOR 0x6 /* src XOR dst */ +#define AO_OR 0x7 /* src OR dst */ +#define AO_NOR 0x8 /* NOT src AND NOT dst */ +#define AO_EQUIV 0x9 /* NOT src XOR dst */ +#define AO_INVERT 0xa /* NOT dst */ +#define AO_OR_REVERSE 0xb /* src OR NOT dst */ +#define AO_COPY_INVERTED 0xc /* NOT src */ +#define AO_OR_INVERTED 0xd /* NOT src OR dst */ +#define AO_NAND 0xe /* NOT src OR NOT dst */ +#define AO_SET 0xf /* 1 */ + +#endif /* _AO_DRAW_H_ */ diff --git a/src/draw/ao_draw_int.h b/src/draw/ao_draw_int.h new file mode 100644 index 00000000..433aa409 --- /dev/null +++ b/src/draw/ao_draw_int.h @@ -0,0 +1,136 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _AO_DRAW_INT_H_ +#define _AO_DRAW_INT_H_ + +static inline uint32_t +ao_expand(uint32_t bits) +{ + return ~((bits & 1)-1); +} + +static inline uint32_t +ao_xor(uint8_t rop, uint32_t fg) +{ + fg = ao_expand(fg); + + return (fg & ao_expand(rop >> 1)) | + (~fg & ao_expand(rop >> 3)); +} + +static inline uint32_t +ao_and(uint8_t rop, uint32_t fg) +{ + fg = ao_expand(fg); + + return (fg & ao_expand(rop ^ (rop >> 1))) | + (~fg & ao_expand((rop>>2) ^ (rop>>3))); +} + +static inline uint32_t +ao_left(uint32_t bits, int16_t shift) { + return bits >> shift; +} + +static inline uint32_t +ao_right(uint32_t bits, int16_t shift) { + return bits << shift; +} + +static inline uint32_t +ao_right_mask(int16_t x) { + if ((AO_UNIT - x) & AO_MASK) + return ao_left(AO_ALLONES,(AO_UNIT - x) & AO_MASK); + else + return 0; +} + +static inline uint32_t +ao_left_mask(int16_t x) { + if (x & AO_MASK) + return ao_right(AO_ALLONES, x & AO_MASK); + else + return 0; +} + +static inline uint32_t +ao_bits_mask(int16_t x, int16_t w) { + return ao_right(AO_ALLONES, x & AO_MASK) & + ao_left(AO_ALLONES,(AO_UNIT - (x + w)) & AO_MASK); +} + +#define ao_mask_bits(x,w,l,n,r) { \ + n = (w); \ + r = ao_right_mask((x)+n); \ + l = ao_left_mask(x); \ + if (l) { \ + n -= AO_UNIT - ((x) & AO_MASK); \ + if (n < 0) { \ + n = 0; \ + l &= r; \ + r = 0; \ + } \ + } \ + n >>= AO_SHIFT; \ +} + +#define ao_clip(val,min,max) do { \ + if (val < min) { \ + val = min; \ + } else if (val > max) { \ + val = max; \ + } \ + } while (0) + +static inline uint32_t +ao_do_mask_rrop(uint32_t dst, uint32_t and, uint32_t xor, uint32_t mask) { + return (dst & (and | ~mask)) ^ (xor & mask); +} + +static inline uint32_t +ao_do_rrop(uint32_t dst, uint32_t and, uint32_t xor) { + return (dst & and) ^ xor; +} + +void +ao_blt(uint32_t *src_line, + int16_t src_stride, + int16_t src_x, + uint32_t *dst_line, + int16_t dst_stride, + int16_t dst_x, + int16_t width, + int16_t height, + uint8_t rop, + uint8_t reverse, + uint8_t upsidedown); + +void +ao_solid(uint32_t and, + uint32_t xor, + uint32_t *dst, + int16_t dst_stride, + int16_t dst_x, + int16_t width, + int16_t height); + +int16_t +ao_glyph(const struct ao_bitmap *dst, + int16_t x, + int16_t y, + uint8_t c, + uint8_t rop); + +#endif /* _AO_DRAW_INT_H_ */ diff --git a/src/draw/ao_font.h b/src/draw/ao_font.h new file mode 100644 index 00000000..5e31dd11 --- /dev/null +++ b/src/draw/ao_font.h @@ -0,0 +1,139 @@ +static const uint8_t glyph_bytes[1568] = { + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x04, 0x0e, 0x1f, 0x0e, 0x04, 0x00, 0x0a, 0x05, + 0x0a, 0x05, 0x0a, 0x05, 0x00, 0x05, 0x07, 0x05, 0x05, 0x0e, 0x04, 0x04, 0x03, 0x01, 0x03, 0x0d, + 0x04, 0x0c, 0x04, 0x03, 0x01, 0x03, 0x06, 0x0a, 0x06, 0x0a, 0x01, 0x01, 0x03, 0x0c, 0x04, 0x0c, + 0x04, 0x04, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0e, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x09, + 0x0b, 0x0d, 0x09, 0x04, 0x04, 0x0c, 0x05, 0x05, 0x05, 0x02, 0x0e, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x1c, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x1f, 0x04, 0x04, 0x04, + 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1f, 0x00, 0x04, 0x04, 0x04, 0x1c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x07, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x04, 0x02, 0x04, 0x08, 0x0e, 0x00, 0x02, 0x04, 0x08, + 0x04, 0x02, 0x0e, 0x00, 0x00, 0x00, 0x0e, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x08, 0x0e, 0x04, 0x0e, + 0x02, 0x00, 0x00, 0x0c, 0x02, 0x07, 0x02, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x04, 0x00, 0x0a, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x1f, 0x0a, 0x1f, 0x0a, 0x00, 0x00, 0x0e, 0x05, 0x0e, + 0x14, 0x0e, 0x00, 0x01, 0x09, 0x04, 0x02, 0x09, 0x08, 0x00, 0x00, 0x02, 0x05, 0x02, 0x05, 0x0a, + 0x00, 0x06, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x02, 0x04, 0x00, 0x02, + 0x04, 0x04, 0x04, 0x04, 0x02, 0x00, 0x00, 0x05, 0x02, 0x07, 0x02, 0x05, 0x00, 0x00, 0x04, 0x04, + 0x1f, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x02, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x08, 0x04, 0x02, 0x01, 0x00, 0x00, + 0x02, 0x05, 0x05, 0x05, 0x05, 0x02, 0x00, 0x02, 0x03, 0x02, 0x02, 0x02, 0x07, 0x00, 0x06, 0x09, + 0x08, 0x04, 0x02, 0x0f, 0x00, 0x0f, 0x08, 0x06, 0x08, 0x09, 0x06, 0x00, 0x04, 0x06, 0x05, 0x0f, + 0x04, 0x04, 0x00, 0x0f, 0x01, 0x07, 0x08, 0x09, 0x06, 0x00, 0x06, 0x01, 0x07, 0x09, 0x09, 0x06, + 0x00, 0x0f, 0x08, 0x04, 0x04, 0x02, 0x02, 0x00, 0x06, 0x09, 0x06, 0x09, 0x09, 0x06, 0x00, 0x06, + 0x09, 0x09, 0x0e, 0x08, 0x06, 0x00, 0x00, 0x06, 0x06, 0x00, 0x06, 0x06, 0x00, 0x00, 0x06, 0x06, + 0x00, 0x06, 0x02, 0x01, 0x00, 0x04, 0x02, 0x01, 0x02, 0x04, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0f, + 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x02, 0x01, 0x00, 0x02, 0x05, 0x04, 0x02, 0x00, 0x02, 0x00, + 0x06, 0x09, 0x0d, 0x0d, 0x01, 0x06, 0x00, 0x06, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x00, 0x07, 0x09, + 0x07, 0x09, 0x09, 0x07, 0x00, 0x06, 0x09, 0x01, 0x01, 0x09, 0x06, 0x00, 0x07, 0x09, 0x09, 0x09, + 0x09, 0x07, 0x00, 0x0f, 0x01, 0x07, 0x01, 0x01, 0x0f, 0x00, 0x0f, 0x01, 0x07, 0x01, 0x01, 0x01, + 0x00, 0x06, 0x09, 0x01, 0x0d, 0x09, 0x0e, 0x00, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x09, 0x00, 0x07, + 0x02, 0x02, 0x02, 0x02, 0x07, 0x00, 0x08, 0x08, 0x08, 0x08, 0x09, 0x06, 0x00, 0x09, 0x05, 0x03, + 0x03, 0x05, 0x09, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0f, 0x00, 0x09, 0x0f, 0x0f, 0x09, 0x09, + 0x09, 0x00, 0x09, 0x0b, 0x0b, 0x0d, 0x0d, 0x09, 0x00, 0x06, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, + 0x07, 0x09, 0x09, 0x07, 0x01, 0x01, 0x00, 0x06, 0x09, 0x09, 0x09, 0x0b, 0x06, 0x08, 0x07, 0x09, + 0x09, 0x07, 0x05, 0x09, 0x00, 0x06, 0x09, 0x02, 0x04, 0x09, 0x06, 0x00, 0x07, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x00, 0x09, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x09, 0x09, 0x09, 0x09, 0x06, 0x06, + 0x00, 0x09, 0x09, 0x09, 0x0f, 0x0f, 0x09, 0x00, 0x09, 0x09, 0x06, 0x06, 0x09, 0x09, 0x00, 0x05, + 0x05, 0x05, 0x02, 0x02, 0x02, 0x00, 0x0f, 0x08, 0x04, 0x02, 0x01, 0x0f, 0x00, 0x07, 0x01, 0x01, + 0x01, 0x01, 0x07, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x00, 0x00, 0x07, 0x04, 0x04, 0x04, 0x04, + 0x07, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, + 0x03, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x01, 0x01, + 0x07, 0x09, 0x09, 0x07, 0x00, 0x00, 0x00, 0x06, 0x01, 0x01, 0x06, 0x00, 0x08, 0x08, 0x0e, 0x09, + 0x09, 0x0e, 0x00, 0x00, 0x00, 0x06, 0x0d, 0x03, 0x06, 0x00, 0x04, 0x0a, 0x02, 0x07, 0x02, 0x02, + 0x00, 0x00, 0x00, 0x0e, 0x09, 0x06, 0x01, 0x0e, 0x01, 0x01, 0x07, 0x09, 0x09, 0x09, 0x00, 0x02, + 0x00, 0x03, 0x02, 0x02, 0x07, 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x05, 0x02, 0x01, 0x01, 0x05, + 0x03, 0x05, 0x09, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x07, 0x00, 0x00, 0x00, 0x05, 0x0f, 0x09, + 0x09, 0x00, 0x00, 0x00, 0x07, 0x09, 0x09, 0x09, 0x00, 0x00, 0x00, 0x06, 0x09, 0x09, 0x06, 0x00, + 0x00, 0x00, 0x07, 0x09, 0x09, 0x07, 0x01, 0x00, 0x00, 0x0e, 0x09, 0x09, 0x0e, 0x08, 0x00, 0x00, + 0x07, 0x09, 0x01, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x03, 0x0c, 0x07, 0x00, 0x02, 0x02, 0x07, 0x02, + 0x02, 0x0c, 0x00, 0x00, 0x00, 0x09, 0x09, 0x09, 0x0e, 0x00, 0x00, 0x00, 0x05, 0x05, 0x05, 0x02, + 0x00, 0x00, 0x00, 0x09, 0x09, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x09, 0x06, 0x06, 0x09, 0x00, 0x00, + 0x00, 0x09, 0x09, 0x0a, 0x04, 0x02, 0x00, 0x00, 0x0f, 0x04, 0x02, 0x0f, 0x00, 0x04, 0x02, 0x03, + 0x02, 0x02, 0x04, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x06, 0x02, 0x02, + 0x01, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x04, + 0x0e, 0x05, 0x05, 0x0e, 0x04, 0x00, 0x0c, 0x02, 0x07, 0x02, 0x0d, 0x00, 0x00, 0x11, 0x0e, 0x0a, + 0x0e, 0x11, 0x00, 0x05, 0x05, 0x02, 0x07, 0x02, 0x02, 0x00, 0x00, 0x04, 0x04, 0x00, 0x04, 0x04, + 0x00, 0x0c, 0x02, 0x06, 0x0a, 0x0c, 0x08, 0x06, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, + 0x11, 0x15, 0x13, 0x15, 0x11, 0x0e, 0x06, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, + 0x09, 0x12, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, + 0x00, 0x00, 0x0e, 0x11, 0x17, 0x13, 0x13, 0x11, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x1f, 0x04, 0x04, 0x1f, 0x00, 0x06, 0x04, + 0x02, 0x06, 0x00, 0x00, 0x00, 0x06, 0x06, 0x04, 0x06, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x09, 0x07, 0x01, 0x0e, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, + 0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x04, + 0x06, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x02, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x12, 0x09, 0x00, 0x00, 0x01, 0x01, 0x01, 0x09, 0x0c, 0x0e, 0x08, 0x01, 0x01, 0x01, 0x0d, 0x08, + 0x04, 0x0c, 0x03, 0x03, 0x02, 0x0b, 0x0c, 0x0e, 0x08, 0x02, 0x00, 0x02, 0x01, 0x05, 0x02, 0x00, + 0x06, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x00, 0x06, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x00, 0x06, 0x09, + 0x09, 0x0f, 0x09, 0x09, 0x00, 0x06, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x00, 0x06, 0x09, 0x09, 0x0f, + 0x09, 0x09, 0x00, 0x06, 0x09, 0x09, 0x0f, 0x09, 0x09, 0x00, 0x0e, 0x05, 0x0d, 0x07, 0x05, 0x0d, + 0x00, 0x06, 0x09, 0x01, 0x01, 0x09, 0x06, 0x02, 0x0f, 0x01, 0x07, 0x01, 0x01, 0x0f, 0x00, 0x0f, + 0x01, 0x07, 0x01, 0x01, 0x0f, 0x00, 0x0f, 0x01, 0x07, 0x01, 0x01, 0x0f, 0x00, 0x0f, 0x01, 0x07, + 0x01, 0x01, 0x0f, 0x00, 0x07, 0x02, 0x02, 0x02, 0x02, 0x07, 0x00, 0x07, 0x02, 0x02, 0x02, 0x02, + 0x07, 0x00, 0x07, 0x02, 0x02, 0x02, 0x02, 0x07, 0x00, 0x07, 0x02, 0x02, 0x02, 0x02, 0x07, 0x00, + 0x07, 0x0a, 0x0b, 0x0a, 0x0a, 0x07, 0x00, 0x0d, 0x09, 0x0b, 0x0d, 0x0d, 0x09, 0x00, 0x06, 0x09, + 0x09, 0x09, 0x09, 0x06, 0x00, 0x06, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x06, 0x09, 0x09, 0x09, + 0x09, 0x06, 0x00, 0x06, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x06, 0x09, 0x09, 0x09, 0x09, 0x06, + 0x00, 0x00, 0x00, 0x09, 0x06, 0x06, 0x09, 0x00, 0x0e, 0x0d, 0x0d, 0x0b, 0x0b, 0x07, 0x00, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x09, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x06, 0x00, 0x09, 0x09, 0x09, 0x09, 0x09, 0x06, 0x00, 0x05, 0x05, 0x05, 0x02, 0x02, + 0x02, 0x00, 0x01, 0x07, 0x09, 0x07, 0x01, 0x01, 0x00, 0x06, 0x09, 0x07, 0x09, 0x0b, 0x05, 0x01, + 0x02, 0x04, 0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x04, 0x02, 0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x04, 0x0a, + 0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x0a, 0x05, 0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x0a, 0x00, 0x0e, 0x09, + 0x0d, 0x0a, 0x00, 0x06, 0x06, 0x0e, 0x09, 0x0d, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0x0d, 0x05, 0x0e, + 0x00, 0x00, 0x00, 0x06, 0x01, 0x01, 0x06, 0x02, 0x02, 0x04, 0x06, 0x0d, 0x03, 0x06, 0x00, 0x04, + 0x02, 0x06, 0x0d, 0x03, 0x06, 0x00, 0x02, 0x05, 0x06, 0x0d, 0x03, 0x06, 0x00, 0x05, 0x00, 0x06, + 0x0d, 0x03, 0x06, 0x00, 0x01, 0x02, 0x03, 0x02, 0x02, 0x07, 0x00, 0x02, 0x01, 0x03, 0x02, 0x02, + 0x07, 0x00, 0x02, 0x05, 0x03, 0x02, 0x02, 0x07, 0x00, 0x05, 0x00, 0x03, 0x02, 0x02, 0x07, 0x00, + 0x02, 0x0c, 0x06, 0x09, 0x09, 0x06, 0x00, 0x0a, 0x05, 0x07, 0x09, 0x09, 0x09, 0x00, 0x02, 0x04, + 0x06, 0x09, 0x09, 0x06, 0x00, 0x04, 0x02, 0x06, 0x09, 0x09, 0x06, 0x00, 0x06, 0x00, 0x06, 0x09, + 0x09, 0x06, 0x00, 0x0a, 0x05, 0x06, 0x09, 0x09, 0x06, 0x00, 0x05, 0x00, 0x06, 0x09, 0x09, 0x06, + 0x00, 0x00, 0x06, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x0d, 0x0b, 0x07, 0x00, 0x02, + 0x04, 0x09, 0x09, 0x09, 0x0e, 0x00, 0x04, 0x02, 0x09, 0x09, 0x09, 0x0e, 0x00, 0x06, 0x00, 0x09, + 0x09, 0x09, 0x0e, 0x00, 0x0a, 0x00, 0x09, 0x09, 0x09, 0x0e, 0x00, 0x04, 0x02, 0x09, 0x09, 0x0a, + 0x04, 0x02, 0x00, 0x01, 0x07, 0x09, 0x09, 0x07, 0x01, 0x0a, 0x00, 0x09, 0x09, 0x0a, 0x04, 0x02, +}; + +static const uint16_t glyph_pos[256] = { + 0, 7, 14, 21, 28, 35, 42, 49, + 56, 63, 70, 77, 84, 91, 98, 105, + 112, 119, 126, 133, 140, 147, 154, 161, + 168, 175, 182, 189, 196, 203, 210, 217, + 224, 231, 238, 245, 252, 259, 266, 273, + 280, 287, 294, 301, 308, 315, 322, 329, + 336, 343, 350, 357, 364, 371, 378, 385, + 392, 399, 406, 413, 420, 427, 434, 441, + 448, 455, 462, 469, 476, 483, 490, 497, + 504, 511, 518, 525, 532, 539, 546, 553, + 560, 567, 574, 581, 588, 595, 602, 609, + 616, 623, 630, 637, 644, 651, 658, 665, + 672, 679, 686, 693, 700, 707, 714, 721, + 728, 735, 742, 749, 756, 763, 770, 777, + 784, 791, 798, 805, 812, 819, 826, 833, + 840, 847, 854, 861, 868, 875, 882, 889, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 896, 903, 910, 917, 924, 931, 938, 945, + 952, 959, 966, 973, 980, 987, 994, 1001, + 1008, 1015, 1022, 1029, 1036, 1043, 1050, 1057, + 1064, 1071, 1078, 1085, 1092, 1099, 1106, 1113, + 1120, 1127, 1134, 1141, 1148, 1155, 1162, 1169, + 1176, 1183, 1190, 1197, 1204, 1211, 1218, 1225, + 1232, 1239, 1246, 1253, 1260, 1267, 1274, 1281, + 1288, 1295, 1302, 1309, 1316, 1323, 1330, 1337, + 1344, 1351, 1358, 1365, 1372, 1379, 1386, 1393, + 1400, 1407, 1414, 1421, 1428, 1435, 1442, 1449, + 1456, 1463, 1470, 1477, 1484, 1491, 1498, 1505, + 1512, 1519, 1526, 1533, 1540, 1547, 1554, 1561, +}; + +#define GLYPH_WIDTH 5 +#define GLYPH_HEIGHT 7 +#define GLYPH_ASCENT 6 diff --git a/src/draw/ao_line.c b/src/draw/ao_line.c new file mode 100644 index 00000000..ed1fc21c --- /dev/null +++ b/src/draw/ao_line.c @@ -0,0 +1,314 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao.h" +#include "ao_draw.h" +#include "ao_draw_int.h" + +#define ao_mask(x,w) (ao_right(AO_ALLONES,(x) & AO_MASK) & \ + ao_left(AO_ALLONES,(FB_UNIT - ((x)+(w))) & AO_MASK)) + + +/* out of clip region codes */ +#define OUT_LEFT 0x08 +#define OUT_RIGHT 0x04 +#define OUT_ABOVE 0x02 +#define OUT_BELOW 0x01 + +/* major axis for bresenham's line */ +#define X_AXIS 0 +#define Y_AXIS 1 + +/* + * Line clipping. Clip to the box, bringing the coordinates forward while + * preserving the actual slope and error + * + * + * X major line, clip X: + * + * adjust_x = -x; + * + * e += adjust_x * e1; + * + * adjust_y = (e + -e3-1) / -e3; + * + * e -= adjust_y / -e3; + * + * X major line, clip Y: + * + * adjust_y = -y; + + * + * e -= adjust_y / -e3; + * + * adjust_x = e / e1; + */ + + + + +static void +ao_bres(const struct ao_bitmap *dst_bitmap, + int16_t signdx, + int16_t signdy, + int16_t axis, + int16_t x1, + int16_t y1, + int16_t e, + int16_t e1, + int16_t e3, + int16_t len, + uint32_t and, + uint32_t xor) +{ + int16_t stride = dst_bitmap->stride; + uint32_t *dst = dst_bitmap->base; + uint32_t mask0, mask; + + mask0 = 1; + if (signdx < 0) + mask0 = ao_right(1, AO_UNIT - 1); + + if (signdy < 0) + stride = -stride; + + dst = dst + y1 * stride + (x1 >> AO_SHIFT); + mask = ao_right(1, x1 & AO_MASK); + + while (len--) { + /* clip each point */ + + *dst = ao_do_mask_rrop(*dst, and, xor, mask); + + if (axis == X_AXIS) { + if (signdx < 0) + mask = ao_left(mask, 1); + else + mask = ao_right(mask, 1); + if (!mask) { + dst += signdx; + mask = mask0; + } + e += e1; + if (e >= 0) { + dst += stride; + e += e3; + } + } else { + dst += stride; + e += e1; + if (e >= 0) { + if (signdx < 0) + mask = ao_left(mask, 1); + else + mask = ao_right(mask, 1); + if (!mask) { + dst += signdx; + mask = mask0; + } + e += e3; + } + } + } +} + +struct ao_cc { + int16_t major; + int16_t minor; + int16_t sign_major; + int16_t sign_minor; + int16_t e; + int16_t e1; + int16_t e3; + int8_t first; +}; + +/* line clipping box */ +struct ao_cbox { + int16_t maj1, min1; + int16_t maj2, min2; +}; + +/* -b <= a, so we need to make a bigger */ +static int16_t +div_ceil(int32_t a, int16_t b) { + return (a + b + b - 1) / b - 1; +} + +static int16_t +div_floor_plus_one(int32_t a, int16_t b) { + return (a + b) / b; +} + +static int8_t +ao_clip_line(struct ao_cc *c, struct ao_cbox *b) +{ + int32_t adjust_major = 0, adjust_minor = 0; + + /* Clip major axis */ + if (c->major < b->maj1) { + if (c->sign_major <= 0) + return FALSE; + adjust_major = b->maj1 - c->major; + } else if (c->major >= b->maj2) { + if (c->sign_major >= 0) + return FALSE; + adjust_major = c->major - (b->maj2-1); + } + + /* Clip minor axis */ + if (c->minor < b->min1) { + if (c->sign_minor <= 0) + return FALSE; + adjust_minor = b->min1 - c->minor; + } else if (c->minor >= b->min2) { + if (c->sign_minor >= 0) + return FALSE; + adjust_minor = c->minor - (b->min2-1); + } + + /* If unclipped, we're done */ + if (adjust_major == 0 && adjust_minor == 0) + return TRUE; + + /* See how much minor adjustment would happen during + * a major clip. This is a bit tricky because line drawing + * isn't symmetrical when the line passes exactly between + * two pixels, we have to pick which one gets drawn + */ + int32_t adj_min; + + if (!c->first) + adj_min = div_ceil(c->e + adjust_major * c->e1, -c->e3); + else + adj_min = div_floor_plus_one(c->e + adjust_major * c->e1, -c->e3); + + if (adj_min < adjust_minor) { + if (c->first) + adjust_major = div_ceil(c->e - adjust_minor * c->e3, c->e1); + else + adjust_major = div_floor_plus_one(c->e - adjust_minor * c->e3, c->e1); + } else { + adjust_minor = adj_min; + } + + c->e += adjust_major * c->e1 + adjust_minor * c->e3; + + c->major += c->sign_major * adjust_major; + c->minor += c->sign_minor * adjust_minor; + + return TRUE; +} + +void +ao_line(const struct ao_bitmap *dst, + int16_t x1, + int16_t y1, + int16_t x2, + int16_t y2, + uint32_t fill, + uint8_t rop) +{ + int16_t adx, ady; + int16_t e, e1, e2, e3; + int16_t signdx = 1, signdy = 1; + int16_t axis; + int16_t len; + struct ao_cc clip_1, clip_2; + struct ao_cbox cbox; + + if ((adx = x2 - x1) < 0) { + adx = -adx; + signdx = -1; + } + if ((ady = y2 - y1) < 0) { + ady = -ady; + signdy = -1; + } + + if (adx > ady) { + axis = X_AXIS; + e1 = ady << 1; + e2 = e1 - (adx << 1); + e = e1 - adx; + + clip_1.major = x1; + clip_1.minor = y1; + clip_2.major = x2; + clip_2.minor = y2; + clip_1.sign_major = signdx; + clip_1.sign_minor = signdy; + + cbox.maj1 = 0; + cbox.maj2 = dst->width; + cbox.min1 = 0; + cbox.min2 = dst->height; + } else { + axis = Y_AXIS; + e1 = adx << 1; + e2 = e1 - (ady << 1); + e = e1 - ady; + + clip_1.major = y1; + clip_1.minor = x1; + clip_2.major = y2; + clip_2.minor = x2; + clip_1.sign_major = signdy; + clip_1.sign_minor = signdx; + + cbox.maj1 = 0; + cbox.maj2 = dst->height; + cbox.min1 = 0; + cbox.min2 = dst->width; + } + + e3 = e2 - e1; + e = e - e1; + + clip_1.first = TRUE; + clip_2.first = FALSE; + clip_2.e = clip_1.e = e; + clip_2.e1 = clip_1.e1 = e1; + clip_2.e3 = clip_1.e3 = e3; + clip_2.sign_major = -clip_1.sign_major; + clip_2.sign_minor = -clip_1.sign_minor; + + if (!ao_clip_line(&clip_1, &cbox)) + return; + + if (!ao_clip_line(&clip_2, &cbox)) + return; + + len = clip_1.sign_major * (clip_2.major - clip_1.major) + clip_2.first; + + if (len <= 0) + return; + + if (adx > ady) { + x1 = clip_1.major; + y1 = clip_1.minor; + } else { + x1 = clip_1.minor; + y1 = clip_1.major; + } + ao_bres(dst, + signdx, + signdy, + axis, + x1, + y1, + clip_1.e, e1, e3, len, + ao_and(rop, fill), + ao_xor(rop, fill)); +} diff --git a/src/draw/ao_pattern.c b/src/draw/ao_pattern.c new file mode 100644 index 00000000..0d1dc765 --- /dev/null +++ b/src/draw/ao_pattern.c @@ -0,0 +1,80 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao.h" +#include "ao_draw.h" +#include "ao_draw_int.h" + +static inline uint32_t +ao_pattern_expand(uint8_t v, uint8_t rot) +{ + uint32_t r; + + if (rot) + v = ao_left(v, 8-rot) | ao_right(v, rot); + r = v; + return (r << 24) | (r << 16) | (r << 8) | (r); +} + +static inline int +min(int a, int b) { + return a < b ? a : b; +} + +void +ao_pattern(const struct ao_bitmap *dst, + int16_t x, + int16_t y, + int16_t width, + int16_t height, + const struct ao_pattern *pattern, + int16_t pat_x, + int16_t pat_y, + uint8_t rop) +{ + uint32_t pat[8]; + + int16_t x2 = x + width; + int16_t y2 = y + height; + + ao_clip(x, 0, dst->width); + ao_clip(x2, 0, dst->width); + ao_clip(y, 0, dst->height); + ao_clip(y2, 0, dst->height); + + if (x < x2 && y < y2) { + int xrot = (x - pat_x) & 7; + int yrot = (y - pat_y) & 7; + int i; + int16_t dst_x, dst_y; + + for (i = 0; i < 8; i++) + pat[(i + yrot) & 7] = ao_pattern_expand(pattern->pattern[i], xrot); + for (dst_y = y; dst_y < y2; dst_y += 8) { + int h = min(y2 - dst_y, 8); + for (dst_x = x; dst_x < x2; dst_x += 8) { + int w = min(x2 - dst_x, 8); + + ao_blt(pat, 1, 0, + dst->base + dst_y * dst->stride, + dst->stride, + dst_x, + w, h, + rop, + 0, 0); + } + } + } +} + diff --git a/src/draw/ao_rect.c b/src/draw/ao_rect.c new file mode 100644 index 00000000..71fa4aea --- /dev/null +++ b/src/draw/ao_rect.c @@ -0,0 +1,46 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao.h" +#include "ao_draw.h" +#include "ao_draw_int.h" + +void +ao_rect(const struct ao_bitmap *dst, + int16_t x, + int16_t y, + int16_t width, + int16_t height, + uint32_t fill, + uint8_t rop) +{ + int16_t x2 = x + width; + int16_t y2 = y + height; + + ao_clip(x, 0, dst->width); + ao_clip(x2, 0, dst->width); + ao_clip(y, 0, dst->height); + ao_clip(y2, 0, dst->height); + + if (x < x2 && y < y2) { + ao_solid(ao_and(rop, fill), + ao_xor(rop, fill), + dst->base + y * dst->stride, + dst->stride, + x, + x2 - x, + y2 - y); + } +} + diff --git a/src/draw/ao_text.c b/src/draw/ao_text.c new file mode 100644 index 00000000..7ce2a623 --- /dev/null +++ b/src/draw/ao_text.c @@ -0,0 +1,65 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao.h" +#include "ao_draw.h" +#include "ao_draw_int.h" +#include "ao_font.h" + +const struct ao_font ao_font = { + .width = GLYPH_WIDTH, + .height = GLYPH_HEIGHT, + .ascent = GLYPH_ASCENT, + .descent = GLYPH_HEIGHT - GLYPH_ASCENT, +}; + +void +ao_text(const struct ao_bitmap *dst, + int16_t x, + int16_t y, + char *string, + uint32_t fill, + uint8_t rop) +{ + uint32_t src[GLYPH_HEIGHT]; + char c; + int h; + + struct ao_bitmap src_bitmap = { + .base = src, + .stride = 1, + .width = GLYPH_WIDTH, + .height = GLYPH_HEIGHT + }; + + y -= GLYPH_ASCENT; + + rop = (rop & 3) | 0x4; + + if ((fill&1) == 0) + rop ^= 3; + + while ((c = *string++)) { + const uint8_t *bytes = &glyph_bytes[glyph_pos[(uint8_t) c]]; + + for (h = 0; h < GLYPH_HEIGHT; h++) + src[h] = bytes[h]; + + ao_copy(dst, + x, y, GLYPH_WIDTH, GLYPH_HEIGHT, + &src_bitmap, + 0, 0, rop); + x += GLYPH_WIDTH; + } +} diff --git a/src/draw/font-convert b/src/draw/font-convert new file mode 100755 index 00000000..1985e418 --- /dev/null +++ b/src/draw/font-convert @@ -0,0 +1,150 @@ +#!/usr/bin/nickle + +typedef struct { + int[] bytes; + int width; + int height; + int encoding; + int location; +} glyph_t; + +typedef struct { + glyph_t[...] glyphs; + int default_char; + int ascent; +} font_t; + +glyph_t +read_glyph(file f) +{ + glyph_t glyph = { .encoding = -1, .bytes = (int[...]){}, .width = 0 }; + + while (!File::end(f)) { + string l = fgets(f); + + string[*] tokens = String::split(l, " "); + if (dim(tokens) == 0) + continue; + + switch (tokens[0]) { + case "ENCODING": + glyph.encoding = atoi(tokens[1]); + break; + case "DWIDTH": + glyph.width = atoi(tokens[1]); + break; + case "BBX": + glyph.height = atoi(tokens[2]); + break; + case "ENDCHAR": + return glyph; + case "BITMAP": + while (!File::end(f)) { + string l = fgets(f); + if (l == "ENDCHAR") + return glyph; + glyph.bytes[dim(glyph.bytes)] = atoi(l, 16); + } + break; + } + } + return glyph; +} + +font_t read_font(file f) { + font_t font = { .glyphs = {}, .default_char = -1 }; + bool in_head = true; + + while (in_head && !File::end(f)) { + string l = File::fgets(f); + + string[*] tokens = String::split(l, " "); + switch (tokens[0]) { + case "DEFAULT_CHAR": + font.default_char = atoi(tokens[1]); + break; + case "FONT_ASCENT": + font.ascent = atoi(tokens[1]); + break; + case "CHARS": + in_head = false; + break; + } + } + while (!File::end(f)) { + glyph_t glyph = read_glyph(f); + if (glyph.encoding == -1) + break; + font.glyphs[dim(font.glyphs)] = glyph; + } + return font; +} + +int +flip_byte(int x) +{ + int dest = 0; + + for (int i = 0; i < 8; i++) + dest |= ((x >> (7 - i)) & 1) << i; + return dest; +} + +void print_font(font_t font) { + int width = font.glyphs[0].width; + int height = font.glyphs[0].height; + int[256] pos = { -1 ... }; + int[...] bytes; + + if (false) { + for (int i = 1; i < dim(font.glyphs); i++) { + if (font.glyphs[i].width != width || + font.glyphs[i].height != height) + { + File::fprintf(stderr, "font not constant size, glyph %d is %dx%d\n", + font.glyphs[i].encoding, font.glyphs[i].width, font.glyphs[i].height); + exit(1); + } + } + } + + if (font.default_char == -1) + font.default_char = font.glyphs[0].encoding; + + /* build byte array */ + for (int i = 0; i < dim(font.glyphs); i++) { + pos[font.glyphs[i].encoding] = dim(bytes); + for (int b = 0; b < dim(font.glyphs[i].bytes); b++) + bytes[dim(bytes)] = font.glyphs[i].bytes[b]; + } + + /* Fill in default glyph */ + for (int i = 0; i < dim(pos); i++) + if (pos[i] == -1) + pos[i] = pos[font.default_char]; + + printf("static const uint8_t glyph_bytes[%d] = {", dim(bytes)); + for (int b = 0; b < dim(bytes); b++) { + if ((b & 15) == 0) + printf("\n\t"); + printf("0x%02x, ", flip_byte(bytes[b])); + } + printf("\n};\n\n"); + + printf("static const uint16_t glyph_pos[%d] = {", dim(pos)); + for (int i = 0; i < dim(pos); i++) { + if ((i & 7) == 0) + printf("\n\t"); + printf("%4d, ", pos[i]); + } + printf("\n};\n\n"); + + printf("#define GLYPH_WIDTH %d\n", width); + printf("#define GLYPH_HEIGHT %d\n", height); + printf("#define GLYPH_ASCENT %d\n", font.ascent); +} + +twixt (file f = File::open(argv[1], "r"); File::close(f)) { + font_t font = read_font(f); + print_font(font); +} diff --git a/src/draw/line.5c b/src/draw/line.5c new file mode 100644 index 00000000..747768b0 --- /dev/null +++ b/src/draw/line.5c @@ -0,0 +1,389 @@ +#!/usr/bin/nickle + +autoimport Cairo; +autoload PRNG; + +int +sign(int x) +{ + return x == 0 ? 0 : x < 0 ? -1 : 1; +} + +int X_AXIS = 0; +int Y_AXIS = 1; + +typedef struct { + int major; + int minor; + int sign_major; + int sign_minor; + int e; + int e1; + int e3; + bool first; +} clip_context; + +typedef struct { + int maj1, min1, maj2, min2; +} clip_box; + +typedef struct { + int x1, y1, x2, y2; +} box; + +typedef struct { + int x, y; +} point; + +typedef struct { + int x1, y1, x2, y2; + box b; + point[] clipped; + point[] run; +} test; + +box bounds = { .x1 = 10, .x2 = 30, .y1 = 10, .y2 = 30 }; + +int +div_ceil(a, b) { + a += b; + assert(a >= 0 && b > 0, "bad divide args %d %d\n", a, b); + return (a + b - 1) // b - 1; +} + +int +div_floor_plus_one(a, b) { + a += b; + assert(a >= 0 && b > 0, "bad divide args %d %d\n", a, b); + return a // b; +} + +bool +clip(*clip_context c, *clip_box b) +{ + int adjust_major = 0, adjust_minor = 0; + + /* Clip major axis */ + if (c->major < b->maj1) { + if (c->sign_major <= 0) + return false; + adjust_major = b->maj1 - c->major; + } else if (c->major >= b->maj2) { + if (c->sign_major >= 0) + return false; + adjust_major = c->major - (b->maj2-1); + } + + /* Clip minor axis */ + if (c->minor < b->min1) { + if (c->sign_minor <= 0) + return false; + adjust_minor = b->min1 - c->minor; + } else if (c->minor >= b->min2) { + if (c->sign_minor >= 0) + return false; + adjust_minor = c->minor - (b->min2-1); + } + + /* If unclipped, we're done */ + if (adjust_major == 0 && adjust_minor == 0) + return true; + + /* See how much minor adjustment would happen during + * a major clip. This is a bit tricky because line drawing + * isn't symmetrical when the line passes exactly between + * two pixels, we have to pick which one gets drawn + */ + int adj_min; + + if (!c->first) + adj_min = div_ceil(c->e + adjust_major * c->e1, -c->e3); + else + adj_min = div_floor_plus_one(c->e + adjust_major * c->e1, -c->e3); + + /* Compare that to the minor clip and pick + * the larger amount. + */ + printf ("\tinitial major %d minor %d error %d e1 %d e3 %d\n", c->major, c->minor, c->e, c->e1, c->e3); + + if (adj_min < adjust_minor) { + printf("\tminor clip dominates %d < %d. adjust major %d -> ", + adj_min, adjust_minor, adjust_major); + if (c->first) + adjust_major = div_ceil(c->e - adjust_minor * c->e3, c->e1); + else + adjust_major = div_floor_plus_one(c->e - adjust_minor * c->e3, c->e1); + printf("%d\n", adjust_major); + } else { + printf("\tminor clip dominates %d > %d. adjust minor %d -> ", + adj_min, adjust_minor, adjust_minor); + adjust_minor = adj_min; + printf("%d\n", adjust_minor); + } + + c->e += adjust_major * c->e1 + adjust_minor * c->e3; + + c->major += c->sign_major * adjust_major; + c->minor += c->sign_minor * adjust_minor; + + printf ("\tadjust major %d adjust minor %d e %d e1 %d e3 %e\n", + adjust_major, adjust_minor, c->e, c->e1, c->e3); + + if (c->e >= 0) + printf ("error positive e %d e1 %d e3 %d\n", + c->e, c->e1, c->e3); + if (c->e < c->e3) + printf ("error magnitude too large e %d e1 %d e3 %d\n", c->e, c->e1, c->e3); + + return true; +} + +test +line(int x1, int y1, int x2, int y2, *box b) { + + int dx = x2 - x1; + int dy = y2 - y1; + int signdx = sign(dx); + int signdy = sign(dy); + int adx = abs(dx); + int ady = abs(dy); + int axis; + int e, e1, e2, e3; + int len; + clip_context clip_1, clip_2; + clip_box c; + bool clipped = false; + test t = { + .x1 = x1, + .y1 = y1, + .x2 = x2, + .y2 = y2, + .b = *b, + .clipped = (point[...]) {}, + .run = (point[...]) {} + }; + + if (adx >= ady) { + axis = X_AXIS; + e1 = ady << 1; + e2 = e1 - (adx << 1); + e = e1 - adx; + len = adx; + + clip_1.major = x1; + clip_1.minor = y1; + clip_2.major = x2; + clip_2.minor = y2; + clip_1.sign_major = signdx; + clip_1.sign_minor = signdy; + + c.maj1 = b->x1; + c.maj2 = b->x2; + c.min1 = b->y1; + c.min2 = b->y2; + } else { + axis = Y_AXIS; + e1 = adx << 1; + e2 = e1 - (ady << 1); + e = e1 - ady; + len = ady; + + clip_1.major = y1; + clip_1.minor = x1; + clip_2.major = y2; + clip_2.minor = x2; + clip_1.sign_major = signdy; + clip_1.sign_minor = signdx; + c.maj1 = b->y1; + c.maj2 = b->y2; + c.min1 = b->x1; + c.min2 = b->x2; + } + + e3 = e2 - e1; + e = e - e1; + + clip_1.first = true; + clip_2.first = false; + clip_2.e = clip_1.e = e; + clip_2.e1 = clip_1.e1 = e1; + clip_2.e3 = clip_1.e3 = e3; + clip_2.sign_major = -clip_1.sign_major; + clip_2.sign_minor = -clip_1.sign_minor; + + printf ("clip start:\n"); + if (!clip(&clip_1, &c)) + clipped = true; + + printf("clip end:\n"); + if (!clip(&clip_2, &c)) + clipped = true; + + int clip_len; + int clip_x, clip_y; + int clip_e; + int x_major, x_minor; + int y_major, y_minor; + + clip_len = clip_1.sign_major * (clip_2.major - clip_1.major); + if (clip_len < 0) + clipped = true; + + int x, y; + + if (axis == X_AXIS) { + x = clip_1.major; + y = clip_1.minor; + x_major = clip_1.sign_major; + x_minor = 0; + y_major = 0; + y_minor = clip_1.sign_minor; + } else { + x = clip_1.minor; + y = clip_1.major; + x_major = 0; + x_minor = clip_1.sign_minor; + y_major = clip_1.sign_major; + y_minor = 0; + } + + clip_e = clip_1.e; + + if (clipped) + clip_len = -1; + + while (clip_len-- >= 0) { + t.clipped[dim(t.clipped)] = (point) { .x = x, .y = y }; + x += x_major; + y += y_major; + clip_e += e1; + if (clip_e >= 0) { + x += x_minor; + y += y_minor; + clip_e += e3; + } + } + + x = x1; + y = y1; + + while (len-- >= 0) { + if (bounds.x1 <= x && x < bounds.x2 && + bounds.y1 <= y && y < bounds.y2) { + t.run[dim(t.run)] = (point) { .x = x, .y = y }; + } + x += x_major; + y += y_major; + e += e1; + if (e >= 0) { + x += x_minor; + y += y_minor; + e += e3; + } + } + return t; +} + +void read_events (Cairo::cairo_t cr) +{ + file event = Cairo::open_event(cr); + + while (!File::end(event)) { + string event_line = File::fgets(event); + if (String::index(event_line, "delete") >= 0) + exit(0); + } +} + +#for (int y = 0; y < 20; y++) + +void +show(cairo_t cr, test t) +{ + rectangle(cr, 0, 0, 40, 40); + set_source_rgba(cr, 1, 1, 1, 1); + fill(cr); + + set_source_rgba(cr, 0, 1, 0, .2); + set_line_width(cr, 0.1); + for (int x = 0; x < 40; x++) { + move_to(cr, 0, x); + line_to(cr, 40, x); + move_to(cr, x, 0); + line_to(cr, x, 40); + } + stroke(cr); + + rectangle(cr, t.b.x1, t.b.y1, t.b.x2 - t.b.x1, t.b.y2 - t.b.y1); + set_line_width(cr, 0.1); + set_source_rgba(cr, 0, 0, 0, 1); + stroke(cr); + + move_to(cr, t.x1+.5, t.y1+.5); + line_to(cr, t.x2+.5, t.y2+.5); + move_to(cr, t.x2, t.y2); + line_to(cr, t.x2+1, t.y2+1); + move_to(cr, t.x2+1, t.y2); + line_to(cr, t.x2, t.y2+1); + stroke(cr); + + void pixels(point[] pt) { + for (int i = 0; i < dim(pt); i++) { + rectangle(cr, pt[i].x, pt[i].y, 1, 1); + } + fill(cr); + } + + set_source_rgba(cr, 1, 0, 0, .5); + pixels(t.clipped); + + set_source_rgba(cr, 0, 0, 1, .5); + pixels(t.run); +} + +bool +compare(test t) +{ + if (dim(t.clipped) != dim(t.run)) + return false; + + for (int i = 0; i < dim(t.clipped); i++) + if (t.clipped[i] != t.run[i]) + return false; + return true; +} + +void +doit(int i) +{ + int n; + *box b = &bounds; + + cairo_t cr = new(800, 800); + + scale(cr, 20, 20); + + for (;;) { + PRNG::srandom(i); + int x1 = PRNG::randint(40); + int x2 = PRNG::randint(40); + int y1 = PRNG::randint(40); + int y2 = PRNG::randint(40); + + test t = line (x1, y1, x2, y2, &bounds); + show(cr, t); + if (!compare(t)) { + printf("line %d -- %d x %d - %d x %d\n", i, x1, y1, x2, y2); + gets(); + } + i++; + } + + read_events(cr); +} + +int i = 0; +if (dim(argv) > 1) + i = atoi(argv[1]); + +doit(i); -- cgit v1.2.3 From 6b39d3093c3b87689717bb03988d160473c53c64 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 20 Nov 2016 00:04:27 -0800 Subject: altos: Add VGA driver for STM32L processors Generates vsync/hsync using timers and pixel data using the SPI port. 320x240 video using 640x480 mode and a 24MHz "pixel" clock. Signed-off-by: Keith Packard --- src/drivers/ao_vga.c | 366 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/drivers/ao_vga.h | 39 ++++++ 2 files changed, 405 insertions(+) create mode 100644 src/drivers/ao_vga.c create mode 100644 src/drivers/ao_vga.h (limited to 'src') diff --git a/src/drivers/ao_vga.c b/src/drivers/ao_vga.c new file mode 100644 index 00000000..2d05d522 --- /dev/null +++ b/src/drivers/ao_vga.c @@ -0,0 +1,366 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao.h" +#include "ao_vga.h" + +/* VGA output from the SPI port + * + * Connections: + * + * STM VGA + * GND 4,6,7,8,9,10 + * HSYNC PA5 13 + * VSYNC PB5 14 + * RGB PB4 1,2,3 + * + * pixel clock PA8 -> PB3 + * pixel enable PA1 -> PA15 + */ + +/* GRF formula for 640x480 yields a pixel clock very close to 24MHz. Pad by + * three scanlines to hit exactly that value + */ + +#define HACTIVE (640) +#define HSYNC_START (656) +#define HSYNC_END (720) +#define HTOTAL (800) + +#define VACTIVE 480 +#define VSYNC_START 481 +#define VSYNC_END 484 +#define VTOTAL 500 + +/* + * The horizontal counter is set so that the end of hsync is reached + * at the maximum counter value. That means that the hblank interval + * is offset by HSYNC_END. + */ + +#define HSYNC (HSYNC_END - HSYNC_START) +#define HBLANK_END (HTOTAL - HSYNC_END) +#define HBLANK_START (HBLANK_END + HACTIVE) + +/* + * The vertical counter is set so that the end of vsync is reached at + * the maximum counter value. That means that the vblank interval is + * offset by VSYNC_END. We send a blank line at the start of the + * frame, so each of these is off by one + */ +#define VSYNC (VSYNC_END - VSYNC_START) +#define VBLANK_END (VTOTAL - VSYNC_END) +#define VBLANK_START (VBLANK_END + VACTIVE) + +#define WIDTH_BYTES (AO_VGA_WIDTH >> 3) +#define SCANOUT ((WIDTH_BYTES+2) >> 1) + +uint32_t ao_vga_fb[AO_VGA_STRIDE * AO_VGA_HEIGHT]; + +const struct ao_bitmap ao_vga_bitmap = { + .base = ao_vga_fb, + .stride = AO_VGA_STRIDE, + .width = AO_VGA_WIDTH, + .height = AO_VGA_HEIGHT +}; + +static uint32_t *scanline; + +#define DMA_INDEX STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_TX) + +#define DMA_CCR(en) ((0 << STM_DMA_CCR_MEM2MEM) | \ + (STM_DMA_CCR_PL_VERY_HIGH << STM_DMA_CCR_PL) | \ + (STM_DMA_CCR_MSIZE_16 << STM_DMA_CCR_MSIZE) | \ + (STM_DMA_CCR_PSIZE_16 << STM_DMA_CCR_PSIZE) | \ + (1 << STM_DMA_CCR_MINC) | \ + (0 << STM_DMA_CCR_PINC) | \ + (0 << STM_DMA_CCR_CIRC) | \ + (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) | \ + (0 << STM_DMA_CCR_TCIE) | \ + (en << STM_DMA_CCR_EN)) + + +void stm_tim2_isr(void) +{ + int16_t line = stm_tim3.cnt; + + if (VBLANK_END <= line && line < VBLANK_START) { + /* Disable */ + stm_dma.channel[DMA_INDEX].ccr = DMA_CCR(0); + /* Reset DMA engine for the next scanline */ + stm_dma.channel[DMA_INDEX].cmar = scanline; + stm_dma.channel[DMA_INDEX].cndtr = SCANOUT; + + /* reset SPI */ + (void) stm_spi1.dr; + (void) stm_spi1.sr; + + /* Enable */ + stm_dma.channel[DMA_INDEX].ccr = DMA_CCR(1); + if (((line - VBLANK_END) & 1)) + scanline += AO_VGA_STRIDE; + } else { + scanline = ao_vga_fb; + } + stm_tim2.sr = 0; +} + + +void +ao_vga_init(void) +{ + uint32_t cfgr; + + /* Initialize spi1 using MISO PB4 for output */ + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN); + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN); + + stm_ospeedr_set(&stm_gpiob, 4, STM_OSPEEDR_40MHz); + stm_afr_set(&stm_gpiob, 4, STM_AFR_AF5); + stm_afr_set(&stm_gpiob, 3, STM_AFR_AF5); + stm_afr_set(&stm_gpioa, 15, STM_AFR_AF5); + + /* turn on SPI */ + stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN); + + stm_spi1.cr1 = ((1 << STM_SPI_CR1_BIDIMODE) | /* Two wire mode */ + (1 << STM_SPI_CR1_BIDIOE) | + (0 << STM_SPI_CR1_CRCEN) | /* CRC disabled */ + (0 << STM_SPI_CR1_CRCNEXT) | + (1 << STM_SPI_CR1_DFF) | + (0 << STM_SPI_CR1_RXONLY) | + (0 << STM_SPI_CR1_SSM) | /* Software SS handling */ + (1 << STM_SPI_CR1_SSI) | /* ... */ + (1 << STM_SPI_CR1_LSBFIRST) | /* Little endian */ + (1 << STM_SPI_CR1_SPE) | /* Enable SPI unit */ + (0 << STM_SPI_CR1_BR) | /* baud rate to pclk/2 */ + (0 << STM_SPI_CR1_MSTR) | + (0 << STM_SPI_CR1_CPOL) | /* Format 0 */ + (0 << STM_SPI_CR1_CPHA)); + stm_spi1.cr2 = ((0 << STM_SPI_CR2_TXEIE) | + (0 << STM_SPI_CR2_RXNEIE) | + (0 << STM_SPI_CR2_ERRIE) | + (0 << STM_SPI_CR2_SSOE) | + (1 << STM_SPI_CR2_TXDMAEN) | + (0 << STM_SPI_CR2_RXDMAEN)); + + (void) stm_spi1.dr; + (void) stm_spi1.sr; + + /* Grab the DMA channel for SPI1 MOSI */ + stm_dma.channel[DMA_INDEX].cpar = &stm_spi1.dr; + stm_dma.channel[DMA_INDEX].cmar = ao_vga_fb; + + /* + * Hsync Configuration + */ + /* Turn on timer 2 */ + stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_TIM2EN); + + /* tim2 runs at full speed */ + stm_tim2.psc = 0; + + /* Disable channels while modifying */ + stm_tim2.ccer = 0; + + /* Channel 1 hsync PWM values */ + stm_tim2.ccr1 = HSYNC; + + /* Channel 2 trigger scanout */ + /* wait for the time to start scanout */ + stm_tim2.ccr2 = HBLANK_END; + + stm_tim2.ccr3 = 32; + + /* Configure channel 1 to output on the pin and + * channel 2 to to set the trigger for the vsync timer + */ + stm_tim2.ccmr1 = ((0 << STM_TIM234_CCMR1_OC2CE) | + (STM_TIM234_CCMR1_OC2M_PWM_MODE_1 << STM_TIM234_CCMR1_OC2M) | + (1 << STM_TIM234_CCMR1_OC2PE) | + (0 << STM_TIM234_CCMR1_OC2FE) | + (STM_TIM234_CCMR1_CC2S_OUTPUT << STM_TIM234_CCMR1_CC2S) | + + (0 << STM_TIM234_CCMR1_OC1CE) | + (STM_TIM234_CCMR1_OC1M_PWM_MODE_1 << STM_TIM234_CCMR1_OC1M) | + (1 << STM_TIM234_CCMR1_OC1PE) | + (0 << STM_TIM234_CCMR1_OC1FE) | + (STM_TIM234_CCMR1_CC1S_OUTPUT << STM_TIM234_CCMR1_CC1S)); + + stm_tim2.ccmr2 = ((0 << STM_TIM234_CCMR2_OC4CE) | + (0 << STM_TIM234_CCMR2_OC4M) | + (0 << STM_TIM234_CCMR2_OC4PE) | + (0 << STM_TIM234_CCMR2_OC4FE) | + (0 << STM_TIM234_CCMR2_CC4S) | + + (0 << STM_TIM234_CCMR2_OC3CE) | + (STM_TIM234_CCMR2_OC3M_PWM_MODE_1 << STM_TIM234_CCMR2_OC3M) | + (1 << STM_TIM234_CCMR2_OC3PE) | + (0 << STM_TIM234_CCMR2_OC3FE) | + (0 << STM_TIM234_CCMR2_CC3S)); + + /* One scanline */ + stm_tim2.arr = HTOTAL; + + stm_tim2.cnt = 0; + + /* Update the register contents */ + stm_tim2.egr |= (1 << STM_TIM234_EGR_UG); + + /* Enable the timer */ + + /* Enable the output */ + stm_tim2.ccer = ((0 << STM_TIM234_CCER_CC2NP) | + (STM_TIM234_CCER_CC2P_ACTIVE_HIGH << STM_TIM234_CCER_CC2P) | + (1 << STM_TIM234_CCER_CC2E) | + (0 << STM_TIM234_CCER_CC1NP) | + (STM_TIM234_CCER_CC1P_ACTIVE_LOW << STM_TIM234_CCER_CC1P) | + (1 << STM_TIM234_CCER_CC1E)); + + stm_tim2.cr2 = ((0 << STM_TIM234_CR2_TI1S) | + (STM_TIM234_CR2_MMS_UPDATE << STM_TIM234_CR2_MMS) | + (0 << STM_TIM234_CR2_CCDS)); + + /* hsync is not a slave timer */ + stm_tim2.smcr = 0; + + /* Send an interrupt on channel 3 */ + stm_tim2.dier = ((1 << STM_TIM234_DIER_CC3IE)); + + stm_tim2.cr1 = ((STM_TIM234_CR1_CKD_1 << STM_TIM234_CR1_CKD) | + (1 << STM_TIM234_CR1_ARPE) | + (STM_TIM234_CR1_CMS_EDGE << STM_TIM234_CR1_CMS) | + (STM_TIM234_CR1_DIR_UP << STM_TIM234_CR1_DIR) | + (0 << STM_TIM234_CR1_OPM) | + (1 << STM_TIM234_CR1_URS) | + (0 << STM_TIM234_CR1_UDIS) | + (0 << STM_TIM234_CR1_CEN)); + + /* Hsync is on PA5 which is Timer 2 CH1 output */ + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN); + stm_ospeedr_set(&stm_gpioa, 5, STM_OSPEEDR_40MHz); + stm_afr_set(&stm_gpioa, 5, STM_AFR_AF1); + + /* pixel transmit enable is on PA1 */ + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN); + stm_ospeedr_set(&stm_gpioa, 1, STM_OSPEEDR_40MHz); + stm_afr_set(&stm_gpioa, 1, STM_AFR_AF1); + + /* + * Vsync configuration + */ + + /* Turn on timer 3, slaved to timer 1 using ITR1 (table 61) */ + stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_TIM3EN); + + /* No prescale */ + stm_tim3.psc = 0; + + /* Channel 1 or 2 vsync PWM values */ + stm_tim3.ccr1 = VSYNC; + stm_tim3.ccr2 = VSYNC; + + stm_tim3.ccmr1 = ((0 << STM_TIM234_CCMR1_OC2CE) | + (STM_TIM234_CCMR1_OC2M_PWM_MODE_1 << STM_TIM234_CCMR1_OC2M) | + (1 << STM_TIM234_CCMR1_OC2PE) | + (0 << STM_TIM234_CCMR1_OC2FE) | + (STM_TIM234_CCMR1_CC2S_OUTPUT << STM_TIM234_CCMR1_CC2S) | + + (0 << STM_TIM234_CCMR1_OC1CE) | + (STM_TIM234_CCMR1_OC1M_PWM_MODE_1 << STM_TIM234_CCMR1_OC1M) | + (1 << STM_TIM234_CCMR1_OC1PE) | + (0 << STM_TIM234_CCMR1_OC1FE) | + (STM_TIM234_CCMR1_CC1S_OUTPUT << STM_TIM234_CCMR1_CC1S)); + + stm_tim3.arr = VTOTAL; + stm_tim3.cnt = 0; + + /* Update the register contents */ + stm_tim3.egr |= (1 << STM_TIM234_EGR_UG); + + /* Enable the timer */ + + /* Enable the output */ + stm_tim3.ccer = ((0 << STM_TIM234_CCER_CC1NP) | + (STM_TIM234_CCER_CC2P_ACTIVE_LOW << STM_TIM234_CCER_CC2P) | + (1 << STM_TIM234_CCER_CC2E) | + (STM_TIM234_CCER_CC1P_ACTIVE_LOW << STM_TIM234_CCER_CC1P) | + (1 << STM_TIM234_CCER_CC1E)); + + stm_tim3.cr2 = ((0 << STM_TIM234_CR2_TI1S) | + (STM_TIM234_CR2_MMS_UPDATE << STM_TIM234_CR2_MMS) | + (0 << STM_TIM234_CR2_CCDS)); + + stm_tim3.smcr = 0; + stm_tim3.smcr = ((0 << STM_TIM234_SMCR_ETP) | + (0 << STM_TIM234_SMCR_ECE) | + (STM_TIM234_SMCR_ETPS_OFF << STM_TIM234_SMCR_ETPS) | + (STM_TIM234_SMCR_ETF_NONE << STM_TIM234_SMCR_ETF) | + (0 << STM_TIM234_SMCR_MSM) | + (STM_TIM234_SMCR_TS_ITR1 << STM_TIM234_SMCR_TS) | + (0 << STM_TIM234_SMCR_OCCS) | + (STM_TIM234_SMCR_SMS_EXTERNAL_CLOCK << STM_TIM234_SMCR_SMS)); + + stm_tim3.dier = 0; + + stm_tim3.cr1 = ((STM_TIM234_CR1_CKD_1 << STM_TIM234_CR1_CKD) | + (1 << STM_TIM234_CR1_ARPE) | + (STM_TIM234_CR1_CMS_EDGE << STM_TIM234_CR1_CMS) | + (STM_TIM234_CR1_DIR_UP << STM_TIM234_CR1_DIR) | + (0 << STM_TIM234_CR1_OPM) | + (1 << STM_TIM234_CR1_URS) | + (0 << STM_TIM234_CR1_UDIS) | + (1 << STM_TIM234_CR1_CEN)); + + /* Vsync is on PB5 which is is Timer 3 CH2 output */ + stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN); + stm_ospeedr_set(&stm_gpiob, 5, STM_OSPEEDR_40MHz); + stm_afr_set(&stm_gpiob, 5, STM_AFR_AF2); + + /* Use MCO for the pixel clock, that appears on PA8 */ + cfgr = stm_rcc.cfgr & ~((STM_RCC_CFGR_MCOPRE_MASK << STM_RCC_CFGR_MCOPRE) | + (STM_RCC_CFGR_MCOSEL_MASK << STM_RCC_CFGR_MCOSEL)); + + cfgr |= ((STM_RCC_CFGR_MCOPRE_DIV_2 << STM_RCC_CFGR_MCOPRE) | + (STM_RCC_CFGR_MCOSEL_SYSCLK << STM_RCC_CFGR_MCOSEL)); + + stm_rcc.cfgr = cfgr; + + stm_ospeedr_set(&stm_gpioa, 8, STM_OSPEEDR_40MHz); + stm_afr_set(&stm_gpioa, 8, STM_AFR_AF0); + + /* Enable the scanline interrupt */ + stm_nvic_set_priority(STM_ISR_TIM2_POS, AO_STM_NVIC_NONMASK_PRIORITY); + stm_nvic_set_enable(STM_ISR_TIM2_POS); +} + +uint8_t enabled; + +void +ao_vga_enable(int enable) +{ + if (enable) { + if (!enabled) { + ++ao_task_minimize_latency; + enabled = 1; + } + stm_tim2.cr1 |= (1 << STM_TIM234_CR1_CEN); + } else { + if (enabled) { + --ao_task_minimize_latency; + enabled = 0; + } + stm_tim2.cr1 &= ~(1 << STM_TIM234_CR1_CEN); + } +} diff --git a/src/drivers/ao_vga.h b/src/drivers/ao_vga.h new file mode 100644 index 00000000..7d9d6b39 --- /dev/null +++ b/src/drivers/ao_vga.h @@ -0,0 +1,39 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _AO_VGA_H_ +#define _AO_VGA_H_ + +#include "ao_draw.h" + +void +ao_vga_init(void); + +void +ao_vga_enable(int active); + +/* Active frame buffer */ +#define AO_VGA_WIDTH 320 +#define AO_VGA_HEIGHT 240 + +/* Pad on the right so that there are zeros on the output after the line */ +#define AO_VGA_HPAD 32 + +#define AO_VGA_STRIDE ((AO_VGA_WIDTH + AO_VGA_HPAD) >> AO_SHIFT) + +extern uint32_t ao_vga_fb[AO_VGA_STRIDE * AO_VGA_HEIGHT]; + +extern const struct ao_bitmap ao_vga_bitmap; + +#endif /* _AO_VGA_H_ */ -- cgit v1.2.3 From c1d52178ce63ebdc44c83d1bca5027942e2d778c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 20 Feb 2017 12:19:42 -0800 Subject: altos: Add PS/2 keyboard driver Interrupt driven, includes standard US keymap. Signed-off-by: Keith Packard --- src/drivers/ao_ps2.c | 419 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/drivers/ao_ps2.h | 220 +++++++++++++++++++++++++++ 2 files changed, 639 insertions(+) create mode 100644 src/drivers/ao_ps2.c create mode 100644 src/drivers/ao_ps2.h (limited to 'src') diff --git a/src/drivers/ao_ps2.c b/src/drivers/ao_ps2.c new file mode 100644 index 00000000..29eecea8 --- /dev/null +++ b/src/drivers/ao_ps2.c @@ -0,0 +1,419 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao.h" +#include "ao_ps2.h" +#include "ao_exti.h" + +static struct ao_fifo ao_ps2_rx_fifo; + +static uint16_t ao_ps2_tx; +static uint8_t ao_ps2_tx_count; + +static AO_TICK_TYPE ao_ps2_tick; +static uint16_t ao_ps2_value; +static uint8_t ao_ps2_count; + +uint8_t ao_ps2_stdin; + +uint8_t ao_ps2_scancode_set; + +#define AO_PS2_CLOCK_MODE(pull) ((pull) | AO_EXTI_MODE_FALLING | AO_EXTI_PRIORITY_MED) + +static void +ao_ps2_isr(void); + +static uint8_t +_ao_ps2_parity(uint8_t value) +{ + uint8_t parity = 1; + uint8_t b; + + for (b = 0; b < 8; b++) { + parity ^= (value & 1); + value >>= 1; + } + return parity; +} + +static int +_ao_ps2_poll(void) +{ + uint8_t u; + if (ao_fifo_empty(ao_ps2_rx_fifo)) { + return AO_READ_AGAIN; + } + ao_fifo_remove(ao_ps2_rx_fifo, u); + + return (int) u; +} + +uint8_t +ao_ps2_get(void) +{ + int c; + ao_arch_block_interrupts(); + while ((c = _ao_ps2_poll()) == AO_READ_AGAIN) + ao_sleep(&ao_ps2_rx_fifo); + ao_arch_release_interrupts(); + return (uint8_t) c; +} + + +int +ao_ps2_poll(void) +{ + int c; + ao_arch_block_interrupts(); + c = _ao_ps2_poll(); + ao_arch_release_interrupts(); + return (uint8_t) c; +} + +void +ao_ps2_put(uint8_t c) +{ + ao_arch_block_interrupts(); + ao_ps2_tx = ((uint16_t) c) | (_ao_ps2_parity(c) << 8) | (3 << 9); + ao_ps2_tx_count = 11; + ao_exti_disable(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT); + ao_arch_release_interrupts(); + + /* pull the clock pin down */ + ao_enable_output(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT, AO_PS2_CLOCK_PIN, 0); + ao_delay(0); + + /* pull the data pin down for the start bit */ + ao_enable_output(AO_PS2_DATA_PORT, AO_PS2_DATA_BIT, AO_PS2_DATA_PIN, 0); + ao_delay(0); + + /* switch back to input mode for the interrupt to work */ + ao_exti_setup(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT, + AO_PS2_CLOCK_MODE(AO_EXTI_MODE_PULL_UP), + ao_ps2_isr); + ao_exti_enable(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT); + + /* wait for the bits to drain */ + while (ao_ps2_tx_count) + ao_sleep(&ao_ps2_tx_count); + +} + +static uint8_t ao_ps2_down[128 / 8]; + +static void +ao_ps2_set_down(uint8_t code, uint8_t value) +{ + uint8_t shift = (code & 0x07); + uint8_t byte = code >> 3; + + ao_ps2_down[byte] = (ao_ps2_down[byte] & ~(1 << shift)) | (value << shift); +} + +uint8_t +ao_ps2_is_down(uint8_t code) +{ + uint8_t shift = (code & 0x07); + uint8_t byte = code >> 3; + + return (ao_ps2_down[byte] >> shift) & 1; +} + +static void +_ao_ps2_set_leds(void) +{ + uint8_t led = 0; + if (ao_ps2_is_down(AO_PS2_CAPS_LOCK)) + led |= AO_PS2_SET_LEDS_CAPS; + if (ao_ps2_is_down(AO_PS2_NUM_LOCK)) + led |= AO_PS2_SET_LEDS_NUM; + if (ao_ps2_is_down(AO_PS2_SCROLL_LOCK)) + led |= AO_PS2_SET_LEDS_SCROLL; + ao_arch_release_interrupts(); + ao_ps2_put(AO_PS2_SET_LEDS); + while (ao_ps2_get() != 0xfa); + ao_ps2_put(led); + ao_arch_block_interrupts(); +} + +static uint8_t +ao_ps2_is_lock(uint8_t code) { + switch (code) { + case AO_PS2_CAPS_LOCK: + case AO_PS2_NUM_LOCK: + case AO_PS2_SCROLL_LOCK: + return 1; + } + return 0; +} + +static void +_ao_ps2_set_scancode_set(uint8_t set) +{ + ao_ps2_scancode_set = set; + ao_arch_release_interrupts(); + ao_ps2_put(AO_PS2_SET_SCAN_CODE_SET); + while (ao_ps2_get() != 0xfa); + ao_ps2_put(set); + ao_ps2_put(AO_PS2_SET_KEY_TYPEMATIC_MAKE_BREAK); + while (ao_ps2_get() != 0xfa); + ao_arch_block_interrupts(); +} + +static int +_ao_ps2_poll_key(void) +{ + int c; + uint8_t set_led = 0; + static uint8_t saw_break; + + c = _ao_ps2_poll(); + if (c < 0) { + if (ao_ps2_scancode_set != 3) { + _ao_ps2_set_scancode_set(3); + } + return c; + } + + if (c == AO_PS2_BREAK) { + saw_break = 1; + return AO_READ_AGAIN; + } + if (c & 0x80) + return AO_READ_AGAIN; + + if (ao_ps2_is_lock(c)) { + if (saw_break) { + saw_break = 0; + return AO_READ_AGAIN; + } + if (ao_ps2_is_down(c)) + saw_break = 1; + set_led = 1; + } + if (saw_break) { + saw_break = 0; + ao_ps2_set_down(c, 0); + c |= 0x80; + } else + ao_ps2_set_down(c, 1); + if (set_led) + _ao_ps2_set_leds(); + + if (ao_ps2_scancode_set != 3) + _ao_ps2_set_scancode_set(3); + + return c; +} + +int +ao_ps2_poll_key(void) +{ + int c; + ao_arch_block_interrupts(); + c = _ao_ps2_poll_key(); + ao_arch_release_interrupts(); + return c; +} + +uint8_t +ao_ps2_get_key(void) +{ + int c; + ao_arch_block_interrupts(); + while ((c = _ao_ps2_poll_key()) == AO_READ_AGAIN) + ao_sleep(&ao_ps2_rx_fifo); + ao_arch_release_interrupts(); + return (uint8_t) c; +} + +static const uint8_t ao_ps2_asciimap[128][2] = { + [AO_PS2_A] = { 'a', 'A' }, + [AO_PS2_B] = { 'b', 'B' }, + [AO_PS2_C] = { 'c', 'C' }, + [AO_PS2_D] = { 'd', 'D' }, + [AO_PS2_E] = { 'e', 'E' }, + [AO_PS2_F] = { 'f', 'F' }, + [AO_PS2_G] = { 'g', 'G' }, + [AO_PS2_H] = { 'h', 'H' }, + [AO_PS2_I] = { 'i', 'I' }, + [AO_PS2_J] = { 'j', 'J' }, + [AO_PS2_K] = { 'k', 'K' }, + [AO_PS2_L] = { 'l', 'L' }, + [AO_PS2_M] = { 'm', 'M' }, + [AO_PS2_N] = { 'n', 'N' }, + [AO_PS2_O] = { 'o', 'O' }, + [AO_PS2_P] = { 'p', 'P' }, + [AO_PS2_Q] = { 'q', 'Q' }, + [AO_PS2_R] = { 'r', 'R' }, + [AO_PS2_S] = { 's', 'S' }, + [AO_PS2_T] = { 't', 'T' }, + [AO_PS2_U] = { 'u', 'U' }, + [AO_PS2_V] = { 'v', 'V' }, + [AO_PS2_W] = { 'w', 'W' }, + [AO_PS2_X] = { 'x', 'X' }, + [AO_PS2_Y] = { 'y', 'Y' }, + [AO_PS2_Z] = { 'z', 'Z' }, + + [AO_PS2_0] = { '0', ')' }, + [AO_PS2_1] = { '1', '!' }, + [AO_PS2_2] = { '2', '@' }, + [AO_PS2_3] = { '3', '#' }, + [AO_PS2_4] = { '4', '$' }, + [AO_PS2_5] = { '5', '%' }, + [AO_PS2_6] = { '6', '^' }, + [AO_PS2_7] = { '7', '&' }, + [AO_PS2_8] = { '8', '*' }, + [AO_PS2_9] = { '9', '(' }, + + [AO_PS2_GRAVE] = { '`', '~' }, + [AO_PS2_HYPHEN] = { '-', '_' }, + [AO_PS2_EQUAL] = { '=', '+' }, + [AO_PS2_BACKSLASH] = { '\\', '|' }, + [AO_PS2_BACKSPACE] = { '\010', '\010' }, + [AO_PS2_SPACE] = { ' ', ' ' }, + [AO_PS2_TAB] = { '\t', '\t' }, + + [AO_PS2_ENTER] = { '\r', '\r' }, + [AO_PS2_ESC] = { '\033', '\033' }, + + [AO_PS2_OPEN_SQ] = { '[', '{' }, + [AO_PS2_DELETE] = { '\177', '\177' }, + + [AO_PS2_KP_TIMES] = { '*', '*' }, + [AO_PS2_KP_PLUS] = { '+', '+' }, + [AO_PS2_KP_ENTER] = { '\r', '\r' }, + [AO_PS2_KP_DECIMAL] = { '.', '.' }, + [AO_PS2_KP_0] = { '0', '0' }, + [AO_PS2_KP_1] = { '1', '1' }, + [AO_PS2_KP_2] = { '2', '2' }, + [AO_PS2_KP_3] = { '3', '3' }, + [AO_PS2_KP_4] = { '4', '4' }, + [AO_PS2_KP_5] = { '5', '5' }, + [AO_PS2_KP_6] = { '6', '6' }, + [AO_PS2_KP_7] = { '7', '7' }, + [AO_PS2_KP_8] = { '8', '8' }, + [AO_PS2_KP_9] = { '9', '9' }, + [AO_PS2_CLOSE_SQ] = { ']', '}' }, + [AO_PS2_SEMICOLON] = { ';', ':' }, + [AO_PS2_ACUTE] = { '\'', '"' }, + [AO_PS2_COMMA] = { ',', '<' }, + [AO_PS2_PERIOD] = { '.', '>' }, + [AO_PS2_SLASH] = { '/', '?' }, +}; + +int +ao_ps2_ascii(uint8_t key) +{ + uint8_t col; + char a; + + /* Skip key releases */ + if (key & 0x80) + return AO_READ_AGAIN; + + col = 0; + if (ao_ps2_is_down(AO_PS2_L_SHIFT) || ao_ps2_is_down(AO_PS2_R_SHIFT)) + col = 1; + + /* caps lock */ + a = ao_ps2_asciimap[key][0]; + if (!a) + return AO_READ_AGAIN; + + if ('a' <= a && a <= 'z') + if (ao_ps2_is_down(AO_PS2_CAPS_LOCK)) + col ^= 1; + a = ao_ps2_asciimap[key][col]; + if ('@' <= a && a <= 0x7f && (ao_ps2_is_down(AO_PS2_L_CTRL) || ao_ps2_is_down(AO_PS2_R_CTRL))) + a &= 0x1f; + return a; +} + +int +_ao_ps2_pollchar(void) +{ + int key; + + key = _ao_ps2_poll_key(); + if (key < 0) + return key; + return ao_ps2_ascii(key); +} + +char +ao_ps2_getchar(void) +{ + int c; + ao_arch_block_interrupts(); + while ((c = _ao_ps2_pollchar()) == AO_READ_AGAIN) + ao_sleep(&ao_ps2_rx_fifo); + ao_arch_release_interrupts(); + return (char) c; +} + +static void +ao_ps2_isr(void) +{ + uint8_t bit; + + if (ao_ps2_tx_count) { + ao_gpio_set(AO_PS2_DATA_PORT, AO_PS2_DATA_BIT, AO_PS2_DATA_PIN, ao_ps2_tx&1); + ao_ps2_tx >>= 1; + ao_ps2_tx_count--; + if (!ao_ps2_tx_count) { + ao_enable_input(AO_PS2_DATA_PORT, AO_PS2_DATA_BIT, AO_EXTI_MODE_PULL_UP); + ao_wakeup(&ao_ps2_tx_count); + } + return; + } + /* reset if its been a while */ + if ((ao_tick_count - ao_ps2_tick) > AO_MS_TO_TICKS(100)) + ao_ps2_count = 0; + ao_ps2_tick = ao_tick_count; + + bit = ao_gpio_get(AO_PS2_DATA_PORT, AO_PS2_DATA_BIT, AO_PS2_DATA_PIN); + if (ao_ps2_count == 0) { + /* check for start bit, ignore if not zero */ + if (bit) + return; + ao_ps2_value = 0; + } else if (ao_ps2_count < 9) { + ao_ps2_value |= (bit << (ao_ps2_count - 1)); + } else if (ao_ps2_count == 10) { + ao_fifo_insert(ao_ps2_rx_fifo, ao_ps2_value); + ao_wakeup(&ao_ps2_rx_fifo); + if (ao_ps2_stdin) + ao_wakeup(&ao_stdin_ready); + ao_ps2_count = 0; + return; + } + ao_ps2_count++; +} + +void +ao_ps2_init(void) +{ + ao_enable_input(AO_PS2_DATA_PORT, AO_PS2_DATA_BIT, + AO_EXTI_MODE_PULL_UP); + + ao_enable_port(AO_PS2_CLOCK_PORT); + + ao_exti_setup(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT, + AO_PS2_CLOCK_MODE(AO_EXTI_MODE_PULL_UP), + ao_ps2_isr); + ao_exti_enable(AO_PS2_CLOCK_PORT, AO_PS2_CLOCK_BIT); + + ao_ps2_scancode_set = 2; +} diff --git a/src/drivers/ao_ps2.h b/src/drivers/ao_ps2.h new file mode 100644 index 00000000..f1f05ee5 --- /dev/null +++ b/src/drivers/ao_ps2.h @@ -0,0 +1,220 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _AO_PS2_H_ +#define _AO_PS2_H_ + +extern uint8_t ao_ps2_stdin; + +int +ao_ps2_poll(void); + +uint8_t +ao_ps2_get(void); + +void +ao_ps2_put(uint8_t b); + +uint8_t +ao_ps2_is_down(uint8_t code); + +int +ao_ps2_poll_key(void); + +uint8_t +ao_ps2_get_key(void); + +int +ao_ps2_ascii(uint8_t key); + +int +_ao_ps2_pollchar(void); + +char +ao_ps2_getchar(void); + +void +ao_ps2_init(void); + +/* From http://computer-engineering.org/ps2keyboard/ */ + +/* Device responds with ACK and then resets */ +#define AO_PS2_RESET 0xff + +/* Device retransmits last byte */ +#define AO_PS2_RESEND 0xfe + +/* Setting key report only works in mode 3 */ + +/* Disable break and typematic for specified mode 3 keys. Terminate with invalid key */ +#define AO_PS2_SET_KEY_MAKE 0xfd + +/* Disable typematic for keys */ +#define AO_PS2_SET_KEY_MAKE_BREAK 0xfc + +/* Disable break code for keys */ +#define AO_PS2_SET_KEY_TYPEMATIC 0xfb + +/* Enable make, break and typematic */ +#define AO_PS2_SET_KEY_TYPEMATIC_MAKE_BREAK 0xfa + +/* Disable break and typematic for all */ +#define AO_PS2_SET_ALL_MAKE 0xf9 + +/* Disable typematic for all */ +#define AO_PS2_SET_ALL_MAKE_BREAK 0xf8 + +/* Disable break for all */ +#define AO_PS2_SET_ALL_TYPEMATIC 0xf7 + +/* Set keyboard to default (repeat, report and scan code set 2) */ +#define AO_PS2_SET_DEFAULT 0xf6 + +/* Disable and reset to default */ +#define AO_PS2_DISABLE 0xf5 + +/* Enable */ +#define AO_PS2_ENABLE 0xf4 + +/* Set repeat rate. Bytes 5-6 are the start delay, bits 0-4 are the rate */ +#define AO_PS2_SET_REPEAT_RATE 0xf3 + +/* Read keyboard id. Returns two bytes */ +#define AO_PS2_GETID 0xf2 + +/* Set scan code (1, 2, or 3) */ +#define AO_PS2_SET_SCAN_CODE_SET 0xf0 + +/* Echo. Keyboard replies with Echo */ +#define AO_PS2_ECHO 0xee + +/* Set LEDs */ +#define AO_PS2_SET_LEDS 0xed +# define AO_PS2_SET_LEDS_SCROLL 0x01 +# define AO_PS2_SET_LEDS_NUM 0x02 +# define AO_PS2_SET_LEDS_CAPS 0x04 + +#define AO_PS2_BREAK 0xf0 +#define AO_PS2_ACK 0xfa +#define AO_PS2_ERROR 0xfc +#define AO_PS2_NAK 0xfe + +/* Scan code set 3 */ + +#define AO_PS2_A 0x1c +#define AO_PS2_B 0x32 +#define AO_PS2_C 0x21 +#define AO_PS2_D 0x23 +#define AO_PS2_E 0x24 +#define AO_PS2_F 0x2b +#define AO_PS2_G 0x34 +#define AO_PS2_H 0x33 +#define AO_PS2_I 0x43 +#define AO_PS2_J 0x3b +#define AO_PS2_K 0x42 +#define AO_PS2_L 0x4b +#define AO_PS2_M 0x3a +#define AO_PS2_N 0x31 +#define AO_PS2_O 0x44 +#define AO_PS2_P 0x4d +#define AO_PS2_Q 0x15 +#define AO_PS2_R 0x2d +#define AO_PS2_S 0x1b +#define AO_PS2_T 0x2c +#define AO_PS2_U 0x3c +#define AO_PS2_V 0x2a +#define AO_PS2_W 0x1d +#define AO_PS2_X 0x22 +#define AO_PS2_Y 0x35 +#define AO_PS2_Z 0x1a +#define AO_PS2_0 0x45 +#define AO_PS2_1 0x16 +#define AO_PS2_2 0x1e +#define AO_PS2_3 0x26 +#define AO_PS2_4 0x25 +#define AO_PS2_5 0x2e +#define AO_PS2_6 0x36 +#define AO_PS2_7 0x3d +#define AO_PS2_8 0x3e +#define AO_PS2_9 0x46 +#define AO_PS2_GRAVE 0x0e +#define AO_PS2_HYPHEN 0x4e +#define AO_PS2_EQUAL 0x55 +#define AO_PS2_BACKSLASH 0x5c +#define AO_PS2_BACKSPACE 0x66 +#define AO_PS2_SPACE 0x29 +#define AO_PS2_TAB 0x0d +#define AO_PS2_CAPS_LOCK 0x14 +#define AO_PS2_L_SHIFT 0x12 +#define AO_PS2_L_CTRL 0x11 +#define AO_PS2_L_WIN 0x8b +#define AO_PS2_L_ALT 0x19 +#define AO_PS2_R_SHIFT 0x59 +#define AO_PS2_R_CTRL 0x58 +#define AO_PS2_R_WIN 0x8c +#define AO_PS2_R_ALT 0x39 +#define AO_PS2_APPS 0x8d +#define AO_PS2_ENTER 0x5a +#define AO_PS2_ESC 0x08 +#define AO_PS2_F1 0x07 +#define AO_PS2_F2 0x0f +#define AO_PS2_F3 0x17 +#define AO_PS2_F4 0x1f +#define AO_PS2_F5 0x27 +#define AO_PS2_F6 0x2f +#define AO_PS2_F7 0x37 +#define AO_PS2_F8 0x3f +#define AO_PS2_F9 0x47 +#define AO_PS2_F10 0x4f +#define AO_PS2_F11 0x56 +#define AO_PS2_F12 0x5e +#define AO_PS2_PRNT_SCRN 0x57 +#define AO_PS2_SCROLL_LOCK 0x5f +#define AO_PS2_PAUSE 0x62 +#define AO_PS2_OPEN_SQ 0x54 +#define AO_PS2_INSERT 0x67 +#define AO_PS2_HOME 0x6e +#define AO_PS2_PG_UP 0x6f +#define AO_PS2_DELETE 0x64 +#define AO_PS2_END 0x65 +#define AO_PS2_PG_DN 0x6d +#define AO_PS2_UP 0x63 +#define AO_PS2_LEFT 0x61 +#define AO_PS2_DOWN 0x60 +#define AO_PS2_RIGHT 0x6a +#define AO_PS2_NUM_LOCK 0x76 +#define AO_PS2_KP_TIMES 0x7e +#define AO_PS2_KP_PLUS 0x7c +#define AO_PS2_KP_ENTER 0x79 +#define AO_PS2_KP_DECIMAL 0x71 +#define AO_PS2_KP_0 0x70 +#define AO_PS2_KP_1 0x69 +#define AO_PS2_KP_2 0x72 +#define AO_PS2_KP_3 0x7a +#define AO_PS2_KP_4 0x6b +#define AO_PS2_KP_5 0x73 +#define AO_PS2_KP_6 0x74 +#define AO_PS2_KP_7 0x6c +#define AO_PS2_KP_8 0x75 +#define AO_PS2_KP_9 0x7d +#define AO_PS2_CLOSE_SQ 0x5b +#define AO_PS2_SEMICOLON 0x4c +#define AO_PS2_ACUTE 0x52 +#define AO_PS2_COMMA 0x41 +#define AO_PS2_PERIOD 0x49 +#define AO_PS2_SLASH 0x4a + +#define AO_PS2_RELEASE_FLAG 0x80 + +#endif /* _AO_PS2_H_ */ -- cgit v1.2.3 From c296acd643698d0128e2f58f91a9cfeea63f580a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 20 Feb 2017 12:21:39 -0800 Subject: altos: Add console driver using VGA and PS/2 Provides an interactive text console. Signed-off-by: Keith Packard --- src/drivers/ao_console.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++ src/drivers/ao_console.h | 24 ++++++++ 2 files changed, 175 insertions(+) create mode 100644 src/drivers/ao_console.c create mode 100644 src/drivers/ao_console.h (limited to 'src') diff --git a/src/drivers/ao_console.c b/src/drivers/ao_console.c new file mode 100644 index 00000000..cbde38c9 --- /dev/null +++ b/src/drivers/ao_console.c @@ -0,0 +1,151 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "ao.h" +#include "ao_console.h" +#include "ao_ps2.h" +#include "ao_vga.h" + +static uint8_t console_row, console_col; + +#define ao_console_bitmap ao_vga_bitmap + +static uint8_t console_rows, console_cols; + +static void +ao_console_scroll(void) +{ + ao_copy(&ao_console_bitmap, + 0, 0, + ao_console_bitmap.width, + ao_console_bitmap.height - ao_font.height, + &ao_console_bitmap, + 0, ao_font.height, + AO_COPY); + ao_rect(&ao_console_bitmap, + 0, + (console_rows - 1) * ao_font.height, + ao_console_bitmap.width, + ao_font.height, + 1, + AO_COPY); +} + +static void +ao_console_cursor(void) +{ + ao_rect(&ao_console_bitmap, + console_col * ao_font.width, + console_row * ao_font.height, + ao_font.width, + ao_font.height, + 1, + AO_XOR); +} + +static void +ao_console_clear(void) +{ + ao_rect(&ao_console_bitmap, + 0, 0, + ao_console_bitmap.width, + ao_console_bitmap.height, + 1, + AO_COPY); +} + +static void +ao_console_space(void) +{ + ao_rect(&ao_console_bitmap, + console_col * ao_font.width, + console_row * ao_font.height, + ao_font.width, + ao_font.height, + 1, + AO_COPY); +} + +static void +ao_console_newline(void) +{ + if (++console_row == console_rows) { + ao_console_scroll(); + console_row--; + } +} + +void +ao_console_putchar(char c) +{ + if (' ' <= c && c < 0x7f) { + char text[2]; + ao_console_space(); + text[0] = c; + text[1] = '\0'; + ao_text(&ao_console_bitmap, + console_col * ao_font.width, + console_row * ao_font.height + ao_font.ascent, + text, + 0, + AO_COPY); + if (++console_col == console_cols) { + console_col = 0; + ao_console_newline(); + } + } else { + ao_console_cursor(); + switch (c) { + case '\r': + console_col = 0; + break; + case '\t': + console_col += 8 - (console_col & 7); + if (console_col >= console_cols) { + console_col = 0; + ao_console_newline(); + } + break; + case '\n': + ao_console_newline(); + break; + case '\f': + console_col = console_row = 0; + ao_console_clear(); + break; + case '\177': + case '\010': + if (console_col) + console_col--; + break; + } + } + ao_console_cursor(); +} + +void +ao_console_init(void) +{ + console_cols = ao_console_bitmap.width / ao_font.width; + console_rows = ao_console_bitmap.height / ao_font.height; +#if CONSOLE_STDIN + ao_ps2_stdin = 1; + ao_add_stdio(_ao_ps2_pollchar, + ao_console_putchar, + NULL); +#endif + ao_console_clear(); + ao_console_cursor(); + ao_vga_enable(1); +} diff --git a/src/drivers/ao_console.h b/src/drivers/ao_console.h new file mode 100644 index 00000000..33d3658a --- /dev/null +++ b/src/drivers/ao_console.h @@ -0,0 +1,24 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _AO_CONSOLE_H_ +#define _AO_CONSOLE_H_ + +void +ao_console_putchar(char c); + +void +ao_console_init(void); + +#endif /* _AO_CONSOLE_H_ */ -- cgit v1.2.3 From 0eadc2d50417408beebd50e4a0e7e12430ed67ef Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 20 Feb 2017 12:16:27 -0800 Subject: altos/stm: Add draw and lisp to make search paths. Signed-off-by: Keith Packard --- src/stm/Makefile.defs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/stm/Makefile.defs b/src/stm/Makefile.defs index 0ba86f5a..66ed4be8 100644 --- a/src/stm/Makefile.defs +++ b/src/stm/Makefile.defs @@ -1,4 +1,4 @@ -vpath % ../stm:../product:../drivers:../kernel:../util:../kalman:../aes:../math:.. +vpath % ../stm:../product:../drivers:../kernel:../util:../kalman:../aes:../math:../draw:../lisp:.. vpath make-altitude ../util vpath make-kalman ../util vpath kalman.5c ../kalman @@ -26,7 +26,7 @@ LIBS=$(PDCLIB_LIBS_M3) -lgcc WARN_FLAGS=-Wall -Wextra -Werror -AO_CFLAGS=-I. -I../stm -I../kernel -I../drivers -I../math -I.. $(PDCLIB_INCLUDES) +AO_CFLAGS=-I. -I../stm -I../kernel -I../drivers -I../math -I../draw -I../lisp -I.. $(PDCLIB_INCLUDES) STM_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m3 -mthumb -Wcast-align \ -ffreestanding -nostdlib $(AO_CFLAGS) $(WARN_FLAGS) -- cgit v1.2.3 From dc4bee9600be22531fd3c5bec15f712eb2e7ed2d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 20 Feb 2017 12:18:58 -0800 Subject: altos: Add stm-vga demo project Uses the VGA and PS/2 drivers to provide an interactive console. Signed-off-by: Keith Packard --- src/stm-vga/Makefile | 83 +++++++++++++++ src/stm-vga/ao_demo.c | 233 ++++++++++++++++++++++++++++++++++++++++++ src/stm-vga/ao_lisp_os.h | 62 +++++++++++ src/stm-vga/ao_lisp_os_save.c | 53 ++++++++++ src/stm-vga/ao_pins.h | 219 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 650 insertions(+) create mode 100644 src/stm-vga/Makefile create mode 100644 src/stm-vga/ao_demo.c create mode 100644 src/stm-vga/ao_lisp_os.h create mode 100644 src/stm-vga/ao_lisp_os_save.c create mode 100644 src/stm-vga/ao_pins.h (limited to 'src') diff --git a/src/stm-vga/Makefile b/src/stm-vga/Makefile new file mode 100644 index 00000000..46a77272 --- /dev/null +++ b/src/stm-vga/Makefile @@ -0,0 +1,83 @@ +# +# AltOS build +# +# + +include ../stm/Makefile.defs + +INC = \ + ao.h \ + ao_arch.h \ + ao_arch_funcs.h \ + ao_boot.h \ + ao_pins.h \ + ao_product.h \ + ao_vga.h \ + ao_draw.h \ + ao_draw_int.h \ + ao_font.h \ + ao_ps2.h + +# +# Common AltOS sources +# +ALTOS_SRC = \ + ao_interrupt.c \ + ao_boot_chain.c \ + ao_product.c \ + ao_romconfig.c \ + ao_cmd.c \ + ao_task.c \ + ao_led.c \ + ao_stdio.c \ + ao_panic.c \ + ao_timer.c \ + ao_lcd_stm.c \ + ao_lcd_font.c \ + ao_vga.c \ + ao_blt.c \ + ao_copy.c \ + ao_rect.c \ + ao_text.c \ + ao_line.c \ + ao_mutex.c \ + ao_dma_stm.c \ + ao_adc_stm.c \ + ao_data.c \ + ao_i2c_stm.c \ + ao_usb_stm.c \ + ao_exti_stm.c \ + ao_ps2.c \ + ao_console.c + +PRODUCT=StmVga-v0.0 +IDPRODUCT=0x000a + +CFLAGS = $(STM_CFLAGS) -g -Os + +PROG=stm-vga-$(VERSION) +ELF=$(PROG).elf +IHX=$(PROG).ihx + +SRC=$(ALTOS_SRC) ao_demo.c +OBJ=$(SRC:.c=.o) + +all: $(ELF) $(IHX) + +$(ELF): Makefile $(OBJ) + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJ) $(LIBS) + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +$(OBJ): $(INC) + +distclean: clean + +clean: + rm -f *.o *.elf *.ihx + rm -f ao_product.h + +install: + +uninstall: diff --git a/src/stm-vga/ao_demo.c b/src/stm-vga/ao_demo.c new file mode 100644 index 00000000..1b443b1f --- /dev/null +++ b/src/stm-vga/ao_demo.c @@ -0,0 +1,233 @@ +/* + * Copyright © 2011 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" +#include +#include +#include +#include +#include +#include +#include +#include + +struct ao_task ball_task; +struct ao_task ps2_task; + +#define BALL_WIDTH 5 +#define BALL_HEIGHT 5 + +static int ball_x; +static int ball_y; +static int ball_dx, ball_dy; + +uint8_t ball_enable; + +void +ao_ball(void) +{ + ball_dx = 1; + ball_dy = 1; + ball_x = 0; + ball_y = 0; + for (;;) { + while (!ball_enable) + ao_sleep(&ball_enable); + for (;;) { + ao_line(&ao_vga_bitmap, + -100, -100, ball_x*2, ball_y*2, + 1, AO_XOR); + ao_text(&ao_vga_bitmap, + ball_x, ball_y - 10, + "Hello, Bdale!", + 1, AO_XOR); + ao_rect(&ao_vga_bitmap, + ball_x, ball_y, + BALL_WIDTH, + BALL_HEIGHT, + 1, + AO_XOR); + ao_delay(AO_MS_TO_TICKS(10)); + ao_rect(&ao_vga_bitmap, + ball_x, ball_y, + BALL_WIDTH, + BALL_HEIGHT, + 1, + AO_XOR); + ao_text(&ao_vga_bitmap, + ball_x, ball_y - 10, + "Hello, Bdale!", + 1, AO_XOR); + ao_line(&ao_vga_bitmap, + -100, -100, ball_x*2, ball_y*2, + 1, AO_XOR); + if (!ball_enable) + break; + ball_x += ball_dx; + ball_y += ball_dy; + if (ball_x + BALL_WIDTH > AO_VGA_WIDTH) { + ball_x = AO_VGA_WIDTH - BALL_WIDTH; + ball_dx = -ball_dx; + } + if (ball_x < 0) { + ball_x = -ball_x; + ball_dx = -ball_dx; + } + if (ball_y + BALL_HEIGHT > AO_VGA_HEIGHT) { + ball_y = AO_VGA_HEIGHT - BALL_HEIGHT; + ball_dy = -ball_dy; + } + if (ball_y < 0) { + ball_y = -ball_y; + ball_dy = -ball_dy; + } + } + } +} + +void +ao_ps2(void) +{ + uint8_t leds = 0; + for (;;) { + uint8_t b = ao_ps2_get(); + printf ("%02x\n", b); + flush(); + if (b == 0x14) { + leds ^= 4; + ao_ps2_put(0xed); + if (ao_ps2_get() == 0xfa) + ao_ps2_put(leds); + } + } +} + +static void +ao_fb_init(void) +{ + ao_rect(&ao_vga_bitmap, + 0, 0, AO_VGA_WIDTH, AO_VGA_HEIGHT, + 1, AO_COPY); + + ao_rect(&ao_vga_bitmap, + 10, 10, 10, 10, + 0, AO_COPY); + + ao_rect(&ao_vga_bitmap, + AO_VGA_WIDTH - 20, 10, 10, 10, + 0, AO_COPY); + + ao_rect(&ao_vga_bitmap, + 10, AO_VGA_HEIGHT - 20, 10, 10, + 0, AO_COPY); + + ao_rect(&ao_vga_bitmap, + AO_VGA_WIDTH - 20, AO_VGA_HEIGHT - 20, 10, 10, + 0, AO_COPY); + + ao_text(&ao_vga_bitmap, + 20, 100, + "Hello, Bdale!", + 0, AO_COPY); + + ao_text(&ao_vga_bitmap, + 1, ao_font.ascent, + "UL", + 0, AO_COPY); + + ao_text(&ao_vga_bitmap, + 1, AO_VGA_HEIGHT - ao_font.descent, + "BL", + 0, AO_COPY); +} + +static void +ao_video_toggle(void) +{ + ao_cmd_decimal(); + if (ao_cmd_lex_i) + ao_fb_init(); + ao_vga_enable(ao_cmd_lex_i); +} + +static void +ao_ball_toggle(void) +{ + ao_cmd_decimal(); + ball_enable = ao_cmd_lex_i; + ao_wakeup(&ball_enable); +} + +static void +ao_ps2_read_keys(void) +{ + char c; + + for (;;) { + c = ao_ps2_getchar(); + printf("%02x %c\n", c, ' ' <= c && c < 0x7f ? c : '.'); + flush(); + if (c == ' ') + break; + } +} + +static void +ao_console_send(void) +{ + char c; + + while ((c = getchar()) != '~') { + ao_console_putchar(c); + flush(); + } +} + +__code struct ao_cmds ao_demo_cmds[] = { + { ao_video_toggle, "V\0Toggle video" }, + { ao_ball_toggle, "B\0Toggle ball" }, + { ao_ps2_read_keys, "K\0Read keys from keyboard" }, + { ao_console_send, "C\0Send data to console, end with ~" }, + { 0, NULL } +}; + +int +main(void) +{ + ao_clock_init(); + + ao_task_init(); + + ao_led_init(LEDS_AVAILABLE); + ao_led_on(AO_LED_GREEN); + ao_led_off(AO_LED_BLUE); + ao_timer_init(); + ao_dma_init(); + ao_cmd_init(); + ao_vga_init(); + ao_usb_init(); + ao_exti_init(); + ao_ps2_init(); + ao_console_init(); + + ao_add_task(&ball_task, ao_ball, "ball"); + ao_cmd_register(&ao_demo_cmds[0]); + + ao_start_scheduler(); + return 0; +} diff --git a/src/stm-vga/ao_lisp_os.h b/src/stm-vga/ao_lisp_os.h new file mode 100644 index 00000000..1993ac44 --- /dev/null +++ b/src/stm-vga/ao_lisp_os.h @@ -0,0 +1,62 @@ +/* + * Copyright © 2016 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_LISP_OS_H_ +#define _AO_LISP_OS_H_ + +#include "ao.h" + +static inline int +ao_lisp_getc() { + static uint8_t at_eol; + int c; + + if (at_eol) { + ao_cmd_readline(); + at_eol = 0; + } + c = ao_cmd_lex(); + if (c == '\n') + at_eol = 1; + return c; +} + +static inline void +ao_lisp_os_flush(void) +{ + flush(); +} + +static inline void +ao_lisp_abort(void) +{ + ao_panic(1); +} + +static inline void +ao_lisp_os_led(int led) +{ + ao_led_set(led); +} + +static inline void +ao_lisp_os_delay(int delay) +{ + ao_delay(AO_MS_TO_TICKS(delay)); +} + +#endif diff --git a/src/stm-vga/ao_lisp_os_save.c b/src/stm-vga/ao_lisp_os_save.c new file mode 100644 index 00000000..7c853990 --- /dev/null +++ b/src/stm-vga/ao_lisp_os_save.c @@ -0,0 +1,53 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include + +extern uint8_t __flash__[]; + +/* saved variables to rebuild the heap + + ao_lisp_atoms + ao_lisp_frame_global + */ + +int +ao_lisp_os_save(void) +{ + int i; + + for (i = 0; i < AO_LISP_POOL_TOTAL; i += 256) { + uint32_t *dst = (uint32_t *) (void *) &__flash__[i]; + uint32_t *src = (uint32_t *) (void *) &ao_lisp_pool[i]; + + ao_flash_page(dst, src); + } + return 1; +} + +int +ao_lisp_os_restore_save(struct ao_lisp_os_save *save, int offset) +{ + memcpy(save, &__flash__[offset], sizeof (struct ao_lisp_os_save)); + return 1; +} + +int +ao_lisp_os_restore(void) +{ + memcpy(ao_lisp_pool, __flash__, AO_LISP_POOL_TOTAL); + return 1; +} diff --git a/src/stm-vga/ao_pins.h b/src/stm-vga/ao_pins.h new file mode 100644 index 00000000..8503c4fd --- /dev/null +++ b/src/stm-vga/ao_pins.h @@ -0,0 +1,219 @@ +/* + * Copyright © 2012 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +/* Bridge SB17 on the board and use the MCO from the other chip */ +#define AO_HSE 8000000 +#define AO_HSE_BYPASS 1 + +/* PLLVCO = 96MHz (so that USB will work) */ +#define AO_PLLMUL 12 +#define AO_RCC_CFGR_PLLMUL (STM_RCC_CFGR_PLLMUL_12) + +/* SYSCLK = 24MHz */ +#define AO_PLLDIV 4 +#define AO_RCC_CFGR_PLLDIV (STM_RCC_CFGR_PLLDIV_4) + +/* HCLK = 24MHZ (CPU clock) */ +#define AO_AHB_PRESCALER 1 +#define AO_RCC_CFGR_HPRE_DIV STM_RCC_CFGR_HPRE_DIV_1 + +/* Run APB1 at HCLK/1 */ +#define AO_APB1_PRESCALER 1 +#define AO_RCC_CFGR_PPRE1_DIV STM_RCC_CFGR_PPRE2_DIV_1 + +/* Run APB2 at HCLK/1 */ +#define AO_APB2_PRESCALER 1 +#define AO_RCC_CFGR_PPRE2_DIV STM_RCC_CFGR_PPRE2_DIV_1 + +/* Allow for non-maskable interrupts at priority 0 */ +#define AO_NONMASK_INTERRUPT 1 + +#define HAS_SERIAL_1 0 +#define USE_SERIAL_1_STDIN 0 +#define SERIAL_1_PB6_PB7 1 +#define SERIAL_1_PA9_PA10 0 + +#define HAS_SERIAL_2 0 +#define USE_SERIAL_2_STDIN 0 +#define SERIAL_2_PA2_PA3 0 +#define SERIAL_2_PD5_PD6 1 + +#define HAS_SERIAL_3 0 +#define USE_SERIAL_3_STDIN 1 +#define SERIAL_3_PB10_PB11 0 +#define SERIAL_3_PC10_PC11 0 +#define SERIAL_3_PD8_PD9 1 + +#define HAS_SPI_1 0 +#define SPI_1_PB3_PB4_PB5 1 +#define SPI_1_OSPEEDR STM_OSPEEDR_10MHz + +#define HAS_SPI_2 0 + +#define HAS_USB 1 +#define HAS_BEEP 0 +#define PACKET_HAS_SLAVE 0 +#define HAS_TASK_QUEUE 1 + +#define CONSOLE_STDIN 1 + +#define AO_STACK_SIZE 1024 + +#define STM_DMA1_3_STOLEN 1 + +#define AO_BOOT_CHAIN 1 + +#define LOW_LEVEL_DEBUG 0 + +#define LED_PORT_ENABLE STM_RCC_AHBENR_GPIOBEN +#define LED_PORT (&stm_gpiob) +#define LED_PIN_GREEN 7 +#define LED_PIN_BLUE 6 +#define AO_LED_GREEN (1 << LED_PIN_GREEN) +#define AO_LED_BLUE (1 << LED_PIN_BLUE) +#define AO_LED_PANIC AO_LED_BLUE + +#define LEDS_AVAILABLE (AO_LED_BLUE | AO_LED_GREEN) + +#define AO_LCD_STM_SEG_ENABLED_0 ( \ + (1 << 0) | /* PA1 */ \ + (1 << 1) | /* PA2 */ \ + (1 << 2) | /* PA3 */ \ + (0 << 3) | /* PA6 */ \ + (0 << 4) | /* PA7 */ \ + (0 << 5) | /* PB0 */ \ + (0 << 6) | /* PB1 */ \ + (1 << 7) | /* PB3 */ \ + (1 << 8) | /* PB4 */ \ + (1 << 9) | /* PB5 */ \ + (1 << 10) | /* PB10 */ \ + (1 << 11) | /* PB11 */ \ + (1 << 12) | /* PB12 */ \ + (1 << 13) | /* PB13 */ \ + (1 << 14) | /* PB14 */ \ + (1 << 15) | /* PB15 */ \ + (1 << 16) | /* PB8 */ \ + (1 << 17) | /* PA15 */ \ + (1 << 18) | /* PC0 */ \ + (1 << 19) | /* PC1 */ \ + (1 << 20) | /* PC2 */ \ + (1 << 21) | /* PC3 */ \ + (0 << 22) | /* PC4 */ \ + (0 << 23) | /* PC5 */ \ + (1 << 24) | /* PC6 */ \ + (1 << 25) | /* PC7 */ \ + (1 << 26) | /* PC8 */ \ + (1 << 27) | /* PC9 */ \ + (1 << 28) | /* PC10 or PD8 */ \ + (1 << 29) | /* PC11 or PD9 */ \ + (0 << 30) | /* PC12 or PD10 */ \ + (0 << 31)) /* PD2 or PD11 */ + +#define AO_LCD_STM_SEG_ENABLED_1 ( \ + (0 << 0) | /* PD12 */ \ + (0 << 1) | /* PD13 */ \ + (0 << 2) | /* PD14 */ \ + (0 << 3) | /* PD15 */ \ + (0 << 4) | /* PE0 */ \ + (0 << 5) | /* PE1 */ \ + (0 << 6) | /* PE2 */ \ + (0 << 7)) /* PE3 */ + +#define AO_LCD_STM_COM_ENABLED ( \ + (1 << 0) | /* PA8 */ \ + (1 << 1) | /* PA9 */ \ + (1 << 2) | /* PA10 */ \ + (1 << 3) | /* PB9 */ \ + (0 << 4) | /* PC10 */ \ + (0 << 5) | /* PC11 */ \ + (0 << 6)) /* PC12 */ + +#define AO_LCD_28_ON_C 1 + +#define AO_LCD_DUTY STM_LCD_CR_DUTY_STATIC + +#define HAS_ADC 1 + +#define AO_ADC_RING 32 + +struct ao_adc { + uint16_t tick; + int16_t idd; + int16_t temp; + int16_t vref; +}; + +#define AO_ADC_IDD 4 +#define AO_ADC_PIN0_PORT (&stm_gpioa) +#define AO_ADC_PIN0_PIN 4 + +#define AO_ADC_RCC_AHBENR ((1 << STM_RCC_AHBENR_GPIOAEN)) +#define AO_ADC_TEMP 16 +#define AO_ADC_VREF 17 + +#define HAS_ADC_TEMP 1 + +#define AO_DATA_RING 32 +#define AO_NUM_ADC 3 + +#define AO_ADC_SQ1 AO_ADC_IDD +#define AO_ADC_SQ2 AO_ADC_TEMP +#define AO_ADC_SQ3 AO_ADC_VREF + +#define HAS_I2C_1 1 +#define I2C_1_PB6_PB7 0 +#define I2C_1_PB8_PB9 1 + +#define HAS_I2C_2 0 +#define I2C_2_PB10_PB11 0 + +#define AO_EVENT 1 + +#define AO_QUADRATURE_COUNT 2 +#define AO_QUADRATURE_MODE AO_EXTI_MODE_PULL_UP + +#define AO_QUADRATURE_0_PORT &stm_gpioc +#define AO_QUADRATURE_0_A 1 +#define AO_QUADRATURE_0_B 0 + +#define AO_QUADRATURE_1_PORT &stm_gpioc +#define AO_QUADRATURE_1_A 3 +#define AO_QUADRATURE_1_B 2 + +#define AO_BUTTON_COUNT 2 +#define AO_BUTTON_MODE AO_EXTI_MODE_PULL_UP + +#define AO_BUTTON_0_PORT &stm_gpioc +#define AO_BUTTON_0 6 + +#define AO_BUTTON_1_PORT &stm_gpioc +#define AO_BUTTON_1 7 + +#define AO_TICK_TYPE uint32_t +#define AO_TICK_SIGNED int32_t + +#define AO_PS2_CLOCK_PORT (&stm_gpioc) +#define AO_PS2_CLOCK_BIT 0 + +#define AO_PS2_DATA_PORT (&stm_gpioc) +#define AO_PS2_DATA_BIT 1 + +#endif /* _AO_PINS_H_ */ -- cgit v1.2.3 From 3c3f5e316c0c2464568db883d50881f5b898abac Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 20 Feb 2017 17:33:37 -0800 Subject: altos/telemini-v3.0: Add beeper defines needed for more general beeper code The beeper code now wants to know which timer, port and pin are in use. Signed-off-by: Keith Packard --- src/telemini-v3.0/ao_pins.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/telemini-v3.0/ao_pins.h b/src/telemini-v3.0/ao_pins.h index be7fd8d0..7249ece7 100644 --- a/src/telemini-v3.0/ao_pins.h +++ b/src/telemini-v3.0/ao_pins.h @@ -69,6 +69,9 @@ /* Beeper is on Tim1 CH3 */ #define BEEPER_CHANNEL 3 +#define BEEPER_TIMER 1 +#define BEEPER_PORT (&stm_gpioa) +#define BEEPER_PIN 10 /* LED */ #define LED_PORT_ENABLE STM_RCC_AHBENR_IOPAEN -- cgit v1.2.3 From 003e9479ad4364d9f7acf189b35f32ccdfd43be0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 20 Feb 2017 16:51:09 -0800 Subject: altos/stmf0: Support tim1 beeper channel other than 3 ch1 was broken and ch2 didn't have any code at all. Signed-off-by: Keith Packard --- src/stmf0/ao_beep_stm.c | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/stmf0/ao_beep_stm.c b/src/stmf0/ao_beep_stm.c index fc83bb63..969538fd 100644 --- a/src/stmf0/ao_beep_stm.c +++ b/src/stmf0/ao_beep_stm.c @@ -66,16 +66,16 @@ ao_beep(uint8_t beep) #if BEEPER_CHANNEL == 1 stm_tim1.ccmr1 = ((0 << STM_TIM1_CCMR1_OC2CE) | - (STM_TIM1_CCMR1_OCM_FROZEN << STM_TIM1_CCMR1_OC2M) | + (STM_TIM1_CCMR_OCM_FROZEN << STM_TIM1_CCMR1_OC2M) | (0 << STM_TIM1_CCMR1_OC2PE) | (0 << STM_TIM1_CCMR1_OC2FE) | - (STM_TIM1_CCMR1_CCS_OUTPUT << STM_TIM1_CCMR1_CC2S) | + (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR1_CC2S) | (0 << STM_TIM1_CCMR1_OC1CE) | - (STM_TIM1_CCMR1_OCM_TOGGLE << STM_TIM1_CCMR1_OC1M) | + (STM_TIM1_CCMR_OCM_TOGGLE << STM_TIM1_CCMR1_OC1M) | (0 << STM_TIM1_CCMR1_OC1PE) | (0 << STM_TIM1_CCMR1_OC1FE) | - (STM_TIM1_CCMR1_CCS_OUTPUT << STM_TIM1_CCMR1_CC1S)); + (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR1_CC1S)); stm_tim1.ccer = ((0 << STM_TIM1_CCER_CC4P) | (0 << STM_TIM1_CCER_CC4E) | @@ -91,6 +91,33 @@ ao_beep(uint8_t beep) (0 << STM_TIM1_CCER_CC1P) | (1 << STM_TIM1_CCER_CC1E)); #endif +#if BEEPER_CHANNEL == 2 + stm_tim1.ccmr1 = ((0 << STM_TIM1_CCMR1_OC2CE) | + (STM_TIM1_CCMR_OCM_TOGGLE << STM_TIM1_CCMR1_OC2M) | + (0 << STM_TIM1_CCMR1_OC2PE) | + (0 << STM_TIM1_CCMR1_OC2FE) | + (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR1_CC2S) | + + (0 << STM_TIM1_CCMR1_OC1CE) | + (STM_TIM1_CCMR_OCM_FROZEN << STM_TIM1_CCMR1_OC1M) | + (0 << STM_TIM1_CCMR1_OC1PE) | + (0 << STM_TIM1_CCMR1_OC1FE) | + (STM_TIM1_CCMR_CCS_OUTPUT << STM_TIM1_CCMR1_CC1S)); + + stm_tim1.ccer = ((0 << STM_TIM1_CCER_CC4P) | + (0 << STM_TIM1_CCER_CC4E) | + (0 << STM_TIM1_CCER_CC3NP) | + (0 << STM_TIM1_CCER_CC3NE) | + (0 << STM_TIM1_CCER_CC3P) | + (0 << STM_TIM1_CCER_CC3E) | + (0 << STM_TIM1_CCER_CC2NP) | + (0 << STM_TIM1_CCER_CC2NE) | + (0 << STM_TIM1_CCER_CC2P) | + (1 << STM_TIM1_CCER_CC2E) | + (0 << STM_TIM1_CCER_CC1NE) | + (0 << STM_TIM1_CCER_CC1P) | + (0 << STM_TIM1_CCER_CC1E)); +#endif #if BEEPER_CHANNEL == 3 stm_tim1.ccmr2 = ((0 << STM_TIM1_CCMR2_OC4CE) | (STM_TIM1_CCMR_OCM_FROZEN << STM_TIM1_CCMR2_OC4M) | @@ -177,7 +204,8 @@ ao_beep_init(void) ao_enable_port(&stm_gpioa); stm_afr_set(&stm_gpioa, 10, STM_AFR_AF2); #else -#error unknown beeper channel + ao_enable_port(BEEPER_PORT); + stm_afr_set(BEEPER_PORT, BEEPER_PIN, STM_AFR_AF2); #endif /* Leave the timer off until requested */ -- cgit v1.2.3 From 9603d737e9ea58217ff2c2dd7c350c7a29fba980 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 20 Feb 2017 17:29:15 -0800 Subject: altos/stmf0: Support timer 2/3 for the beeper Tested on timer 2, all four channels. Signed-off-by: Keith Packard --- src/stmf0/ao_beep_stm.c | 197 ++++++++++++++++++++++++++++++++++++++++++++---- src/stmf0/stm32f0.h | 34 ++++----- 2 files changed, 201 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/stmf0/ao_beep_stm.c b/src/stmf0/ao_beep_stm.c index 969538fd..84ccd93e 100644 --- a/src/stmf0/ao_beep_stm.c +++ b/src/stmf0/ao_beep_stm.c @@ -21,16 +21,51 @@ #error BEEPER_CHANNEL undefined #endif +#ifndef BEEPER_TIMER +#define BEEPER_TIMER 1 +#endif + +#if BEEPER_TIMER == 1 +#define timer stm_tim1 +#define STM_RCC_TIMER STM_RCC_APB2ENR_TIM1EN +#define stm_rcc_enr stm_rcc.apb2enr +#endif + +#if BEEPER_TIMER == 2 +#define timer stm_tim2 +#define STM_RCC_TIMER STM_RCC_APB1ENR_TIM2EN +#define stm_rcc_enr stm_rcc.apb1enr +#endif + +#if BEEPER_TIMER == 3 +#define timer stm_tim3 +#define STM_RCC_TIMER STM_RCC_APB1ENR_TIM3EN +#define stm_rcc_enr stm_rcc.apb1enr +#endif + +#ifndef timer +#error BEEPER_TIMER invalid +#endif + +static inline void +disable(void) +{ + timer.cr1 = 0; +#if BEEPER_TIMER == 1 + timer.bdtr = 0; +#endif + stm_rcc_enr &= ~(1 << STM_RCC_TIMER); +} + void ao_beep(uint8_t beep) { if (beep == 0) { - stm_tim1.cr1 = 0; - stm_tim1.bdtr = 0; - stm_rcc.apb2enr &= ~(1 << STM_RCC_APB2ENR_TIM1EN); + disable(); } else { - stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_TIM1EN); + stm_rcc_enr |= (1 << STM_RCC_TIMER); +#if BEEPER_TIMER == 1 /* Master output enable */ stm_tim1.bdtr = (1 << STM_TIM1_BDTR_MOE); @@ -184,6 +219,149 @@ ao_beep(uint8_t beep) /* Update the values */ stm_tim1.egr = (1 << STM_TIM1_EGR_UG); +#endif +#if BEEPER_TIMER == 2 || BEEPER_TIMER == 3 + + timer.cr2 = ((0 << STM_TIM23_CR2_TI1S) | + (STM_TIM23_CR2_MMS_RESET << STM_TIM23_CR2_MMS) | + (0 << STM_TIM23_CR2_CCDS)); + + /* Set prescaler to match cc1111 clocks + */ + timer.psc = AO_TIM_CLK / 750000; + + /* 1. Select the counter clock (internal, external, prescaler). + * + * Setting SMCR to zero means use the internal clock + */ + + timer.smcr = 0; + + /* 2. Write the desired data in the TIMx_ARR and TIMx_CCRx registers. */ + timer.arr = beep; + timer.ccr1 = beep; + + /* 3. Set the CCxIE and/or CCxDE bits if an interrupt and/or a + * DMA request is to be generated. + */ + /* don't want this */ + + /* 4. Select the output mode. For example, you must write + * OCxM=011, OCxPE=0, CCxP=0 and CCxE=1 to toggle OCx output + * pin when CNT matches CCRx, CCRx preload is not used, OCx + * is enabled and active high. + */ + +#if BEEPER_CHANNEL == 1 + timer.ccmr1 = ((0 << STM_TIM23_CCMR1_OC2CE) | + (STM_TIM23_CCMR1_OC2M_FROZEN << STM_TIM23_CCMR1_OC2M) | + (0 << STM_TIM23_CCMR1_OC2PE) | + (0 << STM_TIM23_CCMR1_OC2FE) | + (STM_TIM23_CCMR1_CC2S_OUTPUT << STM_TIM23_CCMR1_CC2S) | + + (0 << STM_TIM23_CCMR1_OC1CE) | + (STM_TIM23_CCMR1_OC1M_TOGGLE << STM_TIM23_CCMR1_OC1M) | + (0 << STM_TIM23_CCMR1_OC1PE) | + (0 << STM_TIM23_CCMR1_OC1FE) | + (STM_TIM23_CCMR1_CC1S_OUTPUT << STM_TIM23_CCMR1_CC1S)); + + timer.ccer = ((0 << STM_TIM23_CCER_CC4P) | + (0 << STM_TIM23_CCER_CC4E) | + (0 << STM_TIM23_CCER_CC3NP) | + (0 << STM_TIM23_CCER_CC3P) | + (0 << STM_TIM23_CCER_CC3E) | + (0 << STM_TIM23_CCER_CC2NP) | + (0 << STM_TIM23_CCER_CC2P) | + (0 << STM_TIM23_CCER_CC2E) | + (0 << STM_TIM23_CCER_CC1P) | + (1 << STM_TIM23_CCER_CC1E)); +#endif +#if BEEPER_CHANNEL == 2 + timer.ccmr1 = ((0 << STM_TIM23_CCMR1_OC2CE) | + (STM_TIM23_CCMR1_OC2M_TOGGLE << STM_TIM23_CCMR1_OC2M) | + (0 << STM_TIM23_CCMR1_OC2PE) | + (0 << STM_TIM23_CCMR1_OC2FE) | + (STM_TIM23_CCMR1_CC2S_OUTPUT << STM_TIM23_CCMR1_CC2S) | + + (0 << STM_TIM23_CCMR1_OC1CE) | + (STM_TIM23_CCMR1_OC1M_FROZEN << STM_TIM23_CCMR1_OC1M) | + (0 << STM_TIM23_CCMR1_OC1PE) | + (0 << STM_TIM23_CCMR1_OC1FE) | + (STM_TIM23_CCMR1_CC1S_OUTPUT << STM_TIM23_CCMR1_CC1S)); + + timer.ccer = ((0 << STM_TIM23_CCER_CC4P) | + (0 << STM_TIM23_CCER_CC4E) | + (0 << STM_TIM23_CCER_CC3NP) | + (0 << STM_TIM23_CCER_CC3P) | + (0 << STM_TIM23_CCER_CC3E) | + (0 << STM_TIM23_CCER_CC2NP) | + (0 << STM_TIM23_CCER_CC2P) | + (1 << STM_TIM23_CCER_CC2E) | + (0 << STM_TIM23_CCER_CC1P) | + (0 << STM_TIM23_CCER_CC1E)); +#endif +#if BEEPER_CHANNEL == 3 + timer.ccmr2 = ((0 << STM_TIM23_CCMR2_OC4CE) | + (STM_TIM23_CCMR2_OC4M_FROZEN << STM_TIM23_CCMR2_OC4M) | + (0 << STM_TIM23_CCMR2_OC4PE) | + (0 << STM_TIM23_CCMR2_OC4FE) | + (STM_TIM23_CCMR2_CC4S_OUTPUT << STM_TIM23_CCMR2_CC4S) | + + (0 << STM_TIM23_CCMR2_OC3CE) | + (STM_TIM23_CCMR2_OC3M_TOGGLE << STM_TIM23_CCMR2_OC3M) | + (0 << STM_TIM23_CCMR2_OC3PE) | + (0 << STM_TIM23_CCMR2_OC3FE) | + (STM_TIM23_CCMR2_CC3S_OUTPUT << STM_TIM23_CCMR2_CC3S)); + + timer.ccer = ((0 << STM_TIM23_CCER_CC4P) | + (0 << STM_TIM23_CCER_CC4E) | + (0 << STM_TIM23_CCER_CC3NP) | + (0 << STM_TIM23_CCER_CC3P) | + (1 << STM_TIM23_CCER_CC3E) | + (0 << STM_TIM23_CCER_CC2NP) | + (0 << STM_TIM23_CCER_CC2P) | + (0 << STM_TIM23_CCER_CC2E) | + (0 << STM_TIM23_CCER_CC1P) | + (0 << STM_TIM23_CCER_CC1E)); +#endif +#if BEEPER_CHANNEL == 4 + timer.ccmr2 = ((0 << STM_TIM23_CCMR2_OC4CE) | + (STM_TIM23_CCMR2_OC4M_TOGGLE << STM_TIM23_CCMR2_OC4M) | + (0 << STM_TIM23_CCMR2_OC4PE) | + (0 << STM_TIM23_CCMR2_OC4FE) | + (STM_TIM23_CCMR2_CC4S_OUTPUT << STM_TIM23_CCMR2_CC4S) | + + (0 << STM_TIM23_CCMR2_OC3CE) | + (STM_TIM23_CCMR2_OC3M_FROZEN << STM_TIM23_CCMR2_OC3M) | + (0 << STM_TIM23_CCMR2_OC3PE) | + (0 << STM_TIM23_CCMR2_OC3FE) | + (STM_TIM23_CCMR2_CC3S_OUTPUT << STM_TIM23_CCMR2_CC3S)); + + timer.ccer = ((0 << STM_TIM23_CCER_CC4P) | + (1 << STM_TIM23_CCER_CC4E) | + (0 << STM_TIM23_CCER_CC3NP) | + (0 << STM_TIM23_CCER_CC3P) | + (0 << STM_TIM23_CCER_CC3E) | + (0 << STM_TIM23_CCER_CC2NP) | + (0 << STM_TIM23_CCER_CC2P) | + (0 << STM_TIM23_CCER_CC2E) | + (0 << STM_TIM23_CCER_CC1P) | + (0 << STM_TIM23_CCER_CC1E)); +#endif + /* 5. Enable the counter by setting the CEN bit in the TIMx_CR1 register. */ + + timer.cr1 = ((STM_TIM23_CR1_CKD_1 << STM_TIM23_CR1_CKD) | + (0 << STM_TIM23_CR1_ARPE) | + (STM_TIM23_CR1_CMS_EDGE << STM_TIM23_CR1_CMS) | + (0 << STM_TIM23_CR1_DIR) | + (0 << STM_TIM23_CR1_OPM) | + (0 << STM_TIM23_CR1_URS) | + (0 << STM_TIM23_CR1_UDIS) | + (1 << STM_TIM23_CR1_CEN)); + + /* Update the values */ + timer.egr = (1 << STM_TIM23_EGR_UG); +#endif } } @@ -198,16 +376,9 @@ ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant void ao_beep_init(void) { -#if BEEPER_CHANNEL == 3 - /* Our beeper is on PA10, which is hooked to TIM1_CH3. - */ - ao_enable_port(&stm_gpioa); - stm_afr_set(&stm_gpioa, 10, STM_AFR_AF2); -#else ao_enable_port(BEEPER_PORT); stm_afr_set(BEEPER_PORT, BEEPER_PIN, STM_AFR_AF2); -#endif - /* Leave the timer off until requested */ - stm_rcc.apb2enr &= ~(1 << STM_RCC_APB2ENR_TIM1EN); + /* Leave the timer off until requested */ + stm_rcc_enr &= ~(1 << STM_RCC_TIMER); } diff --git a/src/stmf0/stm32f0.h b/src/stmf0/stm32f0.h index 1c33f020..e53a5dfd 100644 --- a/src/stmf0/stm32f0.h +++ b/src/stmf0/stm32f0.h @@ -1812,15 +1812,15 @@ extern struct stm_tim23 stm_tim2, stm_tim3; #define STM_TIM23_CCMR2_OC4CE 15 #define STM_TIM23_CCMR2_OC4M 12 -#define STM_TIM23_CCMR2_OCM_FROZEN 0 -#define STM_TIM23_CCMR2_OCM_SET_HIGH_ON_MATCH 1 -#define STM_TIM23_CCMR2_OCM_SET_LOW_ON_MATCH 2 -#define STM_TIM23_CCMR2_OCM_TOGGLE 3 -#define STM_TIM23_CCMR2_OCM_FORCE_LOW 4 -#define STM_TIM23_CCMR2_OCM_FORCE_HIGH 5 -#define STM_TIM23_CCMR2_OCM_PWM_MODE_1 6 -#define STM_TIM23_CCMR2_OCM_PWM_MODE_2 7 -#define STM_TIM23_CCMR2_OCM_MASK 7 +#define STM_TIM23_CCMR2_OC4M_FROZEN 0 +#define STM_TIM23_CCMR2_OC4M_SET_HIGH_ON_MATCH 1 +#define STM_TIM23_CCMR2_OC4M_SET_LOW_ON_MATCH 2 +#define STM_TIM23_CCMR2_OC4M_TOGGLE 3 +#define STM_TIM23_CCMR2_OC4M_FORCE_LOW 4 +#define STM_TIM23_CCMR2_OC4M_FORCE_HIGH 5 +#define STM_TIM23_CCMR2_OC4M_PWM_MODE_1 6 +#define STM_TIM23_CCMR2_OC4M_PWM_MODE_2 7 +#define STM_TIM23_CCMR2_OC4M_MASK 7 #define STM_TIM23_CCMR2_OC4PE 11 #define STM_TIM23_CCMR2_OC4FE 10 #define STM_TIM23_CCMR2_CC4S 8 @@ -1832,15 +1832,15 @@ extern struct stm_tim23 stm_tim2, stm_tim3; #define STM_TIM23_CCMR2_OC3CE 7 #define STM_TIM23_CCMR2_OC3M 4 -#define STM_TIM23_CCMR2_OCM_FROZEN 0 -#define STM_TIM23_CCMR2_OCM_SET_HIGH_ON_MATCH 1 -#define STM_TIM23_CCMR2_OCM_SET_LOW_ON_MATCH 2 -#define STM_TIM23_CCMR2_OCM_TOGGLE 3 -#define STM_TIM23_CCMR2_OCM_FORCE_LOW 4 -#define STM_TIM23_CCMR2_OCM_FORCE_HIGH 5 +#define STM_TIM23_CCMR2_OC3M_FROZEN 0 +#define STM_TIM23_CCMR2_OC3M_SET_HIGH_ON_MATCH 1 +#define STM_TIM23_CCMR2_OC3M_SET_LOW_ON_MATCH 2 +#define STM_TIM23_CCMR2_OC3M_TOGGLE 3 +#define STM_TIM23_CCMR2_OC3M_FORCE_LOW 4 +#define STM_TIM23_CCMR2_OC3M_FORCE_HIGH 5 #define STM_TIM23_CCMR2_OC3M_PWM_MODE_1 6 -#define STM_TIM23_CCMR2_OCM_PWM_MODE_2 7 -#define STM_TIM23_CCMR2_OCM_MASK 7 +#define STM_TIM23_CCMR2_OC3M_PWM_MODE_2 7 +#define STM_TIM23_CCMR2_OC3M_MASK 7 #define STM_TIM23_CCMR2_OC3PE 11 #define STM_TIM23_CCMR2_OC3FE 2 #define STM_TIM23_CCMR2_CC3S 0 -- cgit v1.2.3 From d1956000ba2e6260977aa669475d3ff725578b55 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 20 Feb 2017 17:32:09 -0800 Subject: altos/lisp: Not quite ready to start making it look like scheme yet Lots more code to write before these symbols can be exposed. Signed-off-by: Keith Packard --- src/lisp/ao_lisp_builtin.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/lisp/ao_lisp_builtin.c b/src/lisp/ao_lisp_builtin.c index 006c32f9..902f60e2 100644 --- a/src/lisp/ao_lisp_builtin.c +++ b/src/lisp/ao_lisp_builtin.c @@ -88,11 +88,12 @@ static const ao_poly builtin_names[] = { [builtin_restore] = _ao_lisp_atom_restore, [builtin_call_cc] = _ao_lisp_atom_call2fcc, [builtin_collect] = _ao_lisp_atom_collect, +#if 0 [builtin_symbolp] = _ao_lisp_atom_symbolp, [builtin_listp] = _ao_lisp_atom_listp, [builtin_stringp] = _ao_lisp_atom_stringp, [builtin_numberp] = _ao_lisp_atom_numberp, - +#endif }; static char * -- cgit v1.2.3 From d1c2a5729da00be9d393015bbaa2d2f58e936d84 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 20 Feb 2017 17:34:43 -0800 Subject: altos/nucleo-32: Update lisp files, add beeper support Signed-off-by: Keith Packard --- src/nucleao-32/Makefile | 18 ++++++++++-------- src/nucleao-32/ao_nucleo.c | 7 +++++++ src/nucleao-32/ao_pins.h | 7 ++++++- 3 files changed, 23 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/nucleao-32/Makefile b/src/nucleao-32/Makefile index 57fb4cde..69049982 100644 --- a/src/nucleao-32/Makefile +++ b/src/nucleao-32/Makefile @@ -27,6 +27,7 @@ ALTOS_SRC = \ ao_config.c \ ao_task.c \ ao_led.c \ + ao_beep_stm.c \ ao_dma_stm.c \ ao_stdio.c \ ao_panic.c \ @@ -35,21 +36,22 @@ ALTOS_SRC = \ ao_usb_stm.c \ ao_serial_stm.c \ ao_flash_stm.c \ - ao_lisp_lex.c \ - ao_lisp_mem.c \ + ao_lisp_atom.c \ + ao_lisp_builtin.c \ ao_lisp_cons.c \ + ao_lisp_error.c \ ao_lisp_eval.c \ - ao_lisp_string.c \ - ao_lisp_atom.c \ + ao_lisp_frame.c \ ao_lisp_int.c \ + ao_lisp_lambda.c \ + ao_lisp_lex.c \ + ao_lisp_mem.c \ ao_lisp_poly.c \ - ao_lisp_builtin.c \ ao_lisp_read.c \ ao_lisp_rep.c \ - ao_lisp_frame.c \ - ao_lisp_error.c \ - ao_lisp_lambda.c \ ao_lisp_save.c \ + ao_lisp_stack.c \ + ao_lisp_string.c \ ao_lisp_os_save.c PRODUCT=Nucleo-32 diff --git a/src/nucleao-32/ao_nucleo.c b/src/nucleao-32/ao_nucleo.c index 3e448865..6b4cbaae 100644 --- a/src/nucleao-32/ao_nucleo.c +++ b/src/nucleao-32/ao_nucleo.c @@ -14,13 +14,19 @@ #include #include +#include static void lisp_cmd() { ao_lisp_read_eval_print(); } +static void beep() { + ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(200)); +} + static const struct ao_cmds blink_cmds[] = { { lisp_cmd, "l\0Run lisp interpreter" }, + { beep, "b\0Beep" }, { 0, 0 } }; @@ -33,6 +39,7 @@ void main(void) ao_dma_init(); ao_usb_init(); ao_serial_init(); + ao_beep_init(); ao_cmd_init(); ao_cmd_register(blink_cmds); ao_start_scheduler(); diff --git a/src/nucleao-32/ao_pins.h b/src/nucleao-32/ao_pins.h index e631db7b..cee4616f 100644 --- a/src/nucleao-32/ao_pins.h +++ b/src/nucleao-32/ao_pins.h @@ -47,7 +47,12 @@ #define HAS_USB 1 #define AO_USB_DIRECTIO 0 #define AO_PA11_PA12_RMP 0 -#define HAS_BEEP 0 +#define HAS_BEEP 1 + +#define BEEPER_TIMER 2 +#define BEEPER_CHANNEL 4 +#define BEEPER_PORT (&stm_gpioa) +#define BEEPER_PIN 3 #define IS_FLASH_LOADER 0 -- cgit v1.2.3 From d318b5cfc1a0312697739576d35cc1a190d88849 Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Sat, 1 Apr 2017 12:23:24 -0600 Subject: first rough cut at skeleton of code for pnpservo .. altos boots and runs --- ao-bringup/turnon_telegps | 12 ++-- src/pnpservo-v1/ao_pins.h | 59 ++++++++++++++++ src/pnpservo-v1/ao_pnpservo.c | 36 ++++++++++ src/pnpservo-v1/flash-loader/.gitignore | 2 + src/pnpservo-v1/flash-loader/ao_pins.h | 37 ++++++++++ src/pnpservo-v1/lambda.ld | 117 ++++++++++++++++++++++++++++++++ 6 files changed, 258 insertions(+), 5 deletions(-) create mode 100644 src/pnpservo-v1/ao_pins.h create mode 100644 src/pnpservo-v1/ao_pnpservo.c create mode 100644 src/pnpservo-v1/flash-loader/.gitignore create mode 100644 src/pnpservo-v1/flash-loader/ao_pins.h create mode 100644 src/pnpservo-v1/lambda.ld (limited to 'src') diff --git a/ao-bringup/turnon_telegps b/ao-bringup/turnon_telegps index ba97d503..b6da2898 100755 --- a/ao-bringup/turnon_telegps +++ b/ao-bringup/turnon_telegps @@ -1,10 +1,12 @@ #!/bin/sh -if [ -x /usr/bin/ao-flash-lpc ]; then - FLASH_LPC=/usr/bin/ao-flash-lpc +if [ -x ../ao-tools/ao-flash/ao-flash-lpc ]; then + FLASH_LPC=../ao-tools/ao-flash/ao-flash-lpc +elif [ -x /usr/bin/ao-flash-lpc ]; then + FLASH_LPC=/usr/bin/ao-flash-lpc else - echo "Can't find ao-flash-lpc! Aborting." - exit 1 + echo "Can't find ao-flash-lpc! Aborting." + exit 1 fi if [ -x /usr/bin/ao-usbload ]; then @@ -14,8 +16,8 @@ else exit 1 fi -VERSION=1.0 PRODUCT=TeleGPS +VERSION=1.0 BASE=`echo $PRODUCT | tr 'A-Z' 'a-z'` echo $FILE diff --git a/src/pnpservo-v1/ao_pins.h b/src/pnpservo-v1/ao_pins.h new file mode 100644 index 00000000..38f3d8e5 --- /dev/null +++ b/src/pnpservo-v1/ao_pins.h @@ -0,0 +1,59 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define LED_PORT_ENABLE STM_RCC_AHBENR_IOPAEN +#define LED_PORT (&stm_gpioa) +#define LED_PIN_RED 9 +#define LED_PIN_GREEN 10 +#define AO_LED_RED (1 << LED_PIN_RED) +#define AO_LED_GREEN (1 << LED_PIN_GREEN) +#define AO_LED_PANIC AO_LED_RED +#define AO_CMD_LEN 128 +#define AO_LISP_POOL_TOTAL 3072 +#define AO_LISP_SAVE 1 +#define AO_STACK_SIZE 1024 + +/* need HSI active to write to flash */ +#define AO_NEED_HSI 1 + +#define LEDS_AVAILABLE (AO_LED_RED | AO_LED_GREEN) + +#define AO_POWER_MANAGEMENT 0 + +/* 48MHz clock based on USB */ +#define AO_HSI48 1 + +/* HCLK = 48MHz */ +#define AO_AHB_PRESCALER 1 +#define AO_RCC_CFGR_HPRE_DIV STM_RCC_CFGR_HPRE_DIV_1 + +/* APB = 48MHz */ +#define AO_APB_PRESCALER 1 +#define AO_RCC_CFGR_PPRE_DIV STM_RCC_CFGR_PPRE_DIV_1 + +#define HAS_USB 1 +#define AO_USB_DIRECTIO 0 +#define AO_PA11_PA12_RMP 1 +#define HAS_BEEP 0 + +#define IS_FLASH_LOADER 0 + +#endif /* _AO_PINS_H_ */ diff --git a/src/pnpservo-v1/ao_pnpservo.c b/src/pnpservo-v1/ao_pnpservo.c new file mode 100644 index 00000000..d4c2d495 --- /dev/null +++ b/src/pnpservo-v1/ao_pnpservo.c @@ -0,0 +1,36 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include + +static const struct ao_cmds blink_cmds[] = { +// { lisp_cmd, "l\0Run lisp interpreter" }, + { 0, 0 } +}; + + +void main(void) +{ + ao_led_init(LEDS_AVAILABLE); + ao_clock_init(); + ao_task_init(); + ao_timer_init(); + ao_dma_init(); + ao_usb_init(); + ao_cmd_init(); + ao_cmd_register(blink_cmds); + ao_start_scheduler(); +} + + diff --git a/src/pnpservo-v1/flash-loader/.gitignore b/src/pnpservo-v1/flash-loader/.gitignore new file mode 100644 index 00000000..86ebb7f2 --- /dev/null +++ b/src/pnpservo-v1/flash-loader/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +lambdakey* diff --git a/src/pnpservo-v1/flash-loader/ao_pins.h b/src/pnpservo-v1/flash-loader/ao_pins.h new file mode 100644 index 00000000..4b788f67 --- /dev/null +++ b/src/pnpservo-v1/flash-loader/ao_pins.h @@ -0,0 +1,37 @@ +/* + * Copyright © 2013 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#include + +/* Pin 5 on debug connector */ + +#define AO_BOOT_PIN 1 +#define AO_BOOT_APPLICATION_GPIO stm_gpioa +#define AO_BOOT_APPLICATION_PIN 15 +#define AO_BOOT_APPLICATION_VALUE 1 +#define AO_BOOT_APPLICATION_MODE AO_EXTI_MODE_PULL_UP + +/* USB */ +#define HAS_USB 1 +#define AO_USB_DIRECTIO 0 +#define AO_PA11_PA12_RMP 1 + +#endif /* _AO_PINS_H_ */ diff --git a/src/pnpservo-v1/lambda.ld b/src/pnpservo-v1/lambda.ld new file mode 100644 index 00000000..5de65eb5 --- /dev/null +++ b/src/pnpservo-v1/lambda.ld @@ -0,0 +1,117 @@ +/* + * Copyright © 2012 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +MEMORY { + rom (rx) : ORIGIN = 0x08001000, LENGTH = 25K + flash (r): ORIGIN = 0x08007400, LENGTH = 3k + ram (!w) : ORIGIN = 0x20000000, LENGTH = 6k - 128 + stack (!w) : ORIGIN = 0x20000000 + 6k - 128, LENGTH = 128 +} + +INCLUDE registers.ld + +EXTERN (stm_interrupt_vector) + +SECTIONS { + /* + * Rom contents + */ + + .interrupt ORIGIN(ram) : AT (ORIGIN(rom)) { + __interrupt_start__ = .; + __interrupt_rom__ = ORIGIN(rom); + *(.interrupt) /* Interrupt vectors */ + __interrupt_end__ = .; + } > ram + + .text ORIGIN(rom) + 0x100 : { + __text_start__ = .; + + /* Ick. What I want is to specify the + * addresses of some global constants so + * that I can find them across versions + * of the application. I can't figure out + * how to make gnu ld do that, so instead + * we just load the two files that include + * these defines in the right order here and + * expect things to 'just work'. Don't change + * the contents of those files, ok? + */ + ao_romconfig.o(.romconfig*) + ao_product.o(.romconfig*) + + *(.text*) /* Executable code */ + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.rodata*) /* Constants */ + + } > rom + __text_end__ = .; + + + /* Boot data which must live at the start of ram so that + * the application and bootloader share the same addresses. + * This must be all uninitialized data + */ + .boot (NOLOAD) : { + __boot_start__ = .; + *(.boot) + . = ALIGN(4); + __boot_end__ = .; + } >ram + + /* Functions placed in RAM (required for flashing) + * + * Align to 8 bytes as that's what the ARM likes text + * segment alignments to be, and if we don't, then + * we end up with a mismatch between the location in + * ROM and the desired location in RAM. I don't + * entirely understand this, but at least this appears + * to work... + */ + + .textram BLOCK(8): { + __data_start__ = .; + __text_ram_start__ = .; + *(.ramtext) + __text_ram_end = .; + } >ram AT>rom + + /* Data -- relocated to RAM, but written to ROM + */ + .data : { + *(.data) /* initialized data */ + . = ALIGN(4); + __data_end__ = .; + } >ram AT>rom + + .bss : { + __bss_start__ = .; + *(.bss) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } >ram + + PROVIDE(end = .); + + PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack)); + + __flash__ = ORIGIN(flash); +} + +ENTRY(start); -- cgit v1.2.3 From 66b06332dadd83c309bbfe02240b7a071fd57ff2 Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Sun, 2 Apr 2017 15:41:56 -0600 Subject: initial skeleton of CortexELF support --- src/cortexelf-v1/ao_cortexelf.c | 51 +++++++++ src/cortexelf-v1/ao_pins.h | 182 ++++++++++++++++++++++++++++++++ src/cortexelf-v1/flash-loader/ao_pins.h | 35 ++++++ 3 files changed, 268 insertions(+) create mode 100644 src/cortexelf-v1/ao_cortexelf.c create mode 100644 src/cortexelf-v1/ao_pins.h create mode 100644 src/cortexelf-v1/flash-loader/ao_pins.h (limited to 'src') diff --git a/src/cortexelf-v1/ao_cortexelf.c b/src/cortexelf-v1/ao_cortexelf.c new file mode 100644 index 00000000..01c5165b --- /dev/null +++ b/src/cortexelf-v1/ao_cortexelf.c @@ -0,0 +1,51 @@ +/* + * Copyright © 2011 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include +#if HAS_STACK_GUARD +#include +#endif + +int +main(void) +{ + ao_clock_init(); + +#if HAS_STACK_GUARD + ao_mpu_init(); +#endif + + ao_task_init(); + ao_serial_init(); + ao_timer_init(); + + ao_spi_init(); + ao_dma_init(); + ao_exti_init(); + + ao_cmd_init(); + + ao_usb_init(); + + ao_config_init(); + + ao_start_scheduler(); + return 0; +} diff --git a/src/cortexelf-v1/ao_pins.h b/src/cortexelf-v1/ao_pins.h new file mode 100644 index 00000000..2c960a6b --- /dev/null +++ b/src/cortexelf-v1/ao_pins.h @@ -0,0 +1,182 @@ +/* + * Copyright © 2012 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define HAS_TASK_QUEUE 1 + +/* 8MHz High speed external crystal */ +#define AO_HSE 8000000 + +/* PLLVCO = 96MHz (so that USB will work) */ +#define AO_PLLMUL 12 +#define AO_RCC_CFGR_PLLMUL (STM_RCC_CFGR_PLLMUL_12) + +/* SYSCLK = 32MHz (no need to go faster than CPU) */ +#define AO_PLLDIV 3 +#define AO_RCC_CFGR_PLLDIV (STM_RCC_CFGR_PLLDIV_3) + +/* HCLK = 32MHz (CPU clock) */ +#define AO_AHB_PRESCALER 1 +#define AO_RCC_CFGR_HPRE_DIV STM_RCC_CFGR_HPRE_DIV_1 + +/* Run APB1 at 16MHz (HCLK/2) */ +#define AO_APB1_PRESCALER 2 +#define AO_RCC_CFGR_PPRE1_DIV STM_RCC_CFGR_PPRE2_DIV_2 + +/* Run APB2 at 16MHz (HCLK/2) */ +#define AO_APB2_PRESCALER 2 +#define AO_RCC_CFGR_PPRE2_DIV STM_RCC_CFGR_PPRE2_DIV_2 + +#define HAS_SERIAL_1 1 +#define USE_SERIAL_1_STDIN 0 +#define SERIAL_1_PB6_PB7 1 +#define SERIAL_1_PA9_PA10 0 + +#define HAS_SERIAL_2 1 +#define USE_SERIAL_2_STDIN 0 +#define SERIAL_2_PA2_PA3 0 +#define SERIAL_2_PD5_PD6 1 + +#define HAS_SERIAL_3 0 +#define USE_SERIAL_3_STDIN 0 +#define SERIAL_3_PB10_PB11 0 +#define SERIAL_3_PC10_PC11 0 +#define SERIAL_3_PD8_PD9 0 + +#define HAS_EEPROM 0 +#define USE_INTERNAL_FLASH 0 +#define USE_EEPROM_CONFIG 0 +#define USE_STORAGE_CONFIG 0 +#define HAS_USB 1 +#define HAS_BEEP 0 +#define HAS_BATTERY_REPORT 0 +#define HAS_RADIO 0 +#define HAS_TELEMETRY 0 +#define HAS_APRS 0 +#define HAS_COMPANION 0 + +#define HAS_SPI_1 0 +#define SPI_1_PA5_PA6_PA7 0 +#define SPI_1_PB3_PB4_PB5 0 +#define SPI_1_PE13_PE14_PE15 0 +#define SPI_1_OSPEEDR STM_OSPEEDR_10MHz + +#define HAS_SPI_2 1 +#define SPI_2_PB13_PB14_PB15 0 +#define SPI_2_PD1_PD3_PD4 1 /* LED displays, microSD */ +#define SPI_2_OSPEEDR STM_OSPEEDR_10MHz + +#define SPI_2_PORT (&stm_gpiod) +#define SPI_2_SCK_PIN 1 +#define SPI_2_MISO_PIN 3 +#define SPI_2_MOSI_PIN 4 + +#define HAS_I2C_1 0 +#define I2C_1_PB8_PB9 0 + +#define HAS_I2C_2 0 +#define I2C_2_PB10_PB11 0 + +#define PACKET_HAS_SLAVE 0 +#define PACKET_HAS_MASTER 0 + +#define LOW_LEVEL_DEBUG 0 + +#define LED_PORT_ENABLE STM_RCC_AHBENR_GPIOCEN +#define LED_PORT (&stm_gpioc) +#define LED_PIN_RED 0 +#define LED_PIN_GREEN 0 +#define AO_LED_RED (1 << LED_PIN_RED) +#define AO_LED_GREEN (1 << LED_PIN_GREEN) + +#define LEDS_AVAILABLE 0 + +#define HAS_GPS 0 +#define HAS_FLIGHT 0 +#define HAS_ADC 0 +#define HAS_ADC_TEMP 0 +#define HAS_LOG 0 + +/* + * Pressure sensor settings + */ +#define HAS_MS5607 0 +#define HAS_MS5611 0 +#define AO_MS5607_PRIVATE_PINS 0 +#define AO_MS5607_CS_PORT (&stm_gpioc) +#define AO_MS5607_CS_PIN 4 +#define AO_MS5607_CS_MASK (1 << AO_MS5607_CS) +#define AO_MS5607_MISO_PORT (&stm_gpioa) +#define AO_MS5607_MISO_PIN 6 +#define AO_MS5607_MISO_MASK (1 << AO_MS5607_MISO) +#define AO_MS5607_SPI_INDEX AO_SPI_1_PA5_PA6_PA7 + +/* + * SPI Flash memory + */ + +#define M25_MAX_CHIPS 0 +#define AO_M25_SPI_CS_PORT (&stm_gpiod) +#define AO_M25_SPI_CS_MASK (1 << 3) +#define AO_M25_SPI_BUS AO_SPI_2_PB13_PB14_PB15 + +#define NUM_CMDS 16 + +/* + * Monitor + */ + +#define HAS_MONITOR 0 +#define LEGACY_MONITOR 0 +#define HAS_MONITOR_PUT 0 +#define AO_MONITOR_LED 0 +#define HAS_RSSI 0 + +/* + * Profiling Viterbi decoding + */ + +#ifndef AO_PROFILE +#define AO_PROFILE 0 +#endif + +/* + * PWM output + */ + +#define NUM_PWM 0 +#define PWM_MAX 20000 +#define AO_PWM_TIMER stm_tim4 +#define AO_PWM_TIMER_ENABLE STM_RCC_APB1ENR_TIM4EN +#define AO_PWM_TIMER_SCALE 32 + +#define AO_PWM_0_GPIO (&stm_gpiod) +#define AO_PWM_0_PIN 12 + +#define AO_PWM_1_GPIO (&stm_gpiod) +#define AO_PWM_1_PIN 13 + +#define AO_PWM_2_GPIO (&stm_gpiod) +#define AO_PWM_2_PIN 14 + +#define AO_PWM_3_GPIO (&stm_gpiod) +#define AO_PWM_3_PIN 15 + +#endif /* _AO_PINS_H_ */ diff --git a/src/cortexelf-v1/flash-loader/ao_pins.h b/src/cortexelf-v1/flash-loader/ao_pins.h new file mode 100644 index 00000000..a34bcb6c --- /dev/null +++ b/src/cortexelf-v1/flash-loader/ao_pins.h @@ -0,0 +1,35 @@ +/* + * Copyright © 2013 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +/* External crystal at 8MHz */ +#define AO_HSE 8000000 + +#include + +/* Companion port cs_companion0 PB6 */ + +#define AO_BOOT_PIN 1 +#define AO_BOOT_APPLICATION_GPIO stm_gpiob +#define AO_BOOT_APPLICATION_PIN 0 +#define AO_BOOT_APPLICATION_VALUE 1 +#define AO_BOOT_APPLICATION_MODE AO_EXTI_MODE_PULL_UP + +#endif /* _AO_PINS_H_ */ -- cgit v1.2.3 From bc150497de8539827177805c7f4430c67ca6762f Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Sun, 2 Apr 2017 15:47:14 -0600 Subject: makefiles too --- src/cortexelf-v1/Makefile | 115 +++++++++++++++++++++++++++++++++ src/cortexelf-v1/flash-loader/Makefile | 8 +++ 2 files changed, 123 insertions(+) create mode 100644 src/cortexelf-v1/Makefile create mode 100644 src/cortexelf-v1/flash-loader/Makefile (limited to 'src') diff --git a/src/cortexelf-v1/Makefile b/src/cortexelf-v1/Makefile new file mode 100644 index 00000000..a645d222 --- /dev/null +++ b/src/cortexelf-v1/Makefile @@ -0,0 +1,115 @@ +# +# AltOS build +# +# + +include ../stm/Makefile.defs + +INC = \ + ao.h \ + ao_arch.h \ + ao_arch_funcs.h \ + ao_boot.h \ + ao_pins.h \ + ao_kalman.h \ + ao_product.h \ + ao_profile.h \ + ao_task.h \ + ao_whiten.h \ + ao_quaternion.h \ + math.h \ + ao_mpu.h \ + stm32l.h \ + math.h \ + Makefile + +# +# Common AltOS sources +# +# ao_hmc5883.c + +#PROFILE=ao_profile.c +#PROFILE_DEF=-DAO_PROFILE=1 + +#STACK_GUARD=ao_mpu_stm.c +#STACK_GUARD_DEF=-DHAS_STACK_GUARD=1 + +MATH_SRC=\ + ef_acos.c \ + ef_sqrt.c \ + ef_rem_pio2.c \ + kf_cos.c \ + kf_sin.c \ + kf_rem_pio2.c \ + sf_copysign.c \ + sf_cos.c \ + sf_fabs.c \ + sf_floor.c \ + sf_scalbn.c \ + sf_sin.c \ + ef_log.c + +ALTOS_SRC = \ + ao_boot_chain.c \ + ao_interrupt.c \ + ao_product.c \ + ao_romconfig.c \ + ao_cmd.c \ + ao_config.c \ + ao_task.c \ + ao_led.c \ + ao_stdio.c \ + ao_panic.c \ + ao_timer.c \ + ao_mutex.c \ + ao_serial_stm.c \ + ao_ignite.c \ + ao_freq.c \ + ao_dma_stm.c \ + ao_spi_stm.c \ + ao_storage.c \ + ao_m25.c \ + ao_usb_stm.c \ + ao_exti_stm.c \ + ao_i2c_stm.c \ + ao_convert_volt.c \ + $(MATH_SRC) \ + $(PROFILE) \ + $(SAMPLE_PROFILE) \ + $(STACK_GUARD) + +PRODUCT=CortexELF-v1 +PRODUCT_DEF=-DCORTEXELF +IDPRODUCT=0x000a + +CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g + +PROGNAME=cortexelf-v1 +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +SRC=$(ALTOS_SRC) ao_cortexelf.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) altos.ld + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +../altitude-pa.h: make-altitude-pa + nickle $< > $@ + +$(OBJ): $(INC) + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean: clean + +clean: + rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx + rm -f ao_product.h + +install: + +uninstall: diff --git a/src/cortexelf-v1/flash-loader/Makefile b/src/cortexelf-v1/flash-loader/Makefile new file mode 100644 index 00000000..19cf84e4 --- /dev/null +++ b/src/cortexelf-v1/flash-loader/Makefile @@ -0,0 +1,8 @@ +# +# AltOS flash loader build +# +# + +TOPDIR=../.. +HARDWARE=cortexelf-v1 +include $(TOPDIR)/stm/Makefile-flash.defs -- cgit v1.2.3 From 9f451db9889cd578c3032356fd2aa4b5ed45878d Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Sun, 2 Apr 2017 15:47:31 -0600 Subject: capture pnpservo makefiles too --- src/pnpservo-v1/Makefile | 72 +++++++++++++++++++++++++++++++++++ src/pnpservo-v1/flash-loader/Makefile | 8 ++++ 2 files changed, 80 insertions(+) create mode 100644 src/pnpservo-v1/Makefile create mode 100644 src/pnpservo-v1/flash-loader/Makefile (limited to 'src') diff --git a/src/pnpservo-v1/Makefile b/src/pnpservo-v1/Makefile new file mode 100644 index 00000000..8606b1ae --- /dev/null +++ b/src/pnpservo-v1/Makefile @@ -0,0 +1,72 @@ +# +# AltOS build +# +# + +include ../stmf0/Makefile.defs + +INC = \ + ao.h \ + ao_arch.h \ + ao_arch_funcs.h \ + ao_boot.h \ + ao_pins.h \ + ao_product.h \ + ao_task.h \ + stm32f0.h \ + Makefile + +ALTOS_SRC = \ + ao_boot_chain.c \ + ao_interrupt.c \ + ao_product.c \ + ao_romconfig.c \ + ao_cmd.c \ + ao_config.c \ + ao_task.c \ + ao_led.c \ + ao_dma_stm.c \ + ao_stdio.c \ + ao_mutex.c \ + ao_panic.c \ + ao_timer.c \ + ao_usb_stm.c \ + ao_flash_stm.c + +PRODUCT=PNPservo-v1 +PRODUCT_DEF=-DPNPSERVO +IDPRODUCT=0x000a + +CFLAGS = $(PRODUCT_DEF) -I. $(STMF0_CFLAGS) -Os -g + +LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Tlambda.ld + +PROGNAME=pnpservo-v1 +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +SRC=$(ALTOS_SRC) ao_pnpservo.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) lambda.ld altos.ld + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +$(OBJ): $(INC) + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +load: $(PROG) + stm-load $(PROG) + +distclean: clean + +clean: + rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx + rm -f ao_product.h + +install: + +uninstall: diff --git a/src/pnpservo-v1/flash-loader/Makefile b/src/pnpservo-v1/flash-loader/Makefile new file mode 100644 index 00000000..3283380c --- /dev/null +++ b/src/pnpservo-v1/flash-loader/Makefile @@ -0,0 +1,8 @@ +# +# AltOS flash loader build +# +# + +TOPDIR=../.. +HARDWARE=pnpservo-v1 +include $(TOPDIR)/stmf0/Makefile-flash.defs -- cgit v1.2.3 From 637d522c6a15b47051103ccc3626be3206a7a2df Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 2 Apr 2017 15:04:09 -0700 Subject: cortexelf-v1: Add ps/2 and vga with graphics Start hooking up devices with known drivers. Signed-off-by: Keith Packard --- src/cortexelf-v1/Makefile | 37 +++------ src/cortexelf-v1/ao_cortexelf.c | 172 ++++++++++++++++++++++++++++++++++++++++ src/cortexelf-v1/ao_pins.h | 9 +++ 3 files changed, 194 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/cortexelf-v1/Makefile b/src/cortexelf-v1/Makefile index a645d222..e0fdc8fd 100644 --- a/src/cortexelf-v1/Makefile +++ b/src/cortexelf-v1/Makefile @@ -15,18 +15,17 @@ INC = \ ao_product.h \ ao_profile.h \ ao_task.h \ - ao_whiten.h \ - ao_quaternion.h \ math.h \ ao_mpu.h \ stm32l.h \ math.h \ + ao_vga.h \ + ao_draw.h \ + ao_draw_int.h \ + ao_font.h \ + ao_ps2.h \ Makefile -# -# Common AltOS sources -# -# ao_hmc5883.c #PROFILE=ao_profile.c #PROFILE_DEF=-DAO_PROFILE=1 @@ -34,20 +33,6 @@ INC = \ #STACK_GUARD=ao_mpu_stm.c #STACK_GUARD_DEF=-DHAS_STACK_GUARD=1 -MATH_SRC=\ - ef_acos.c \ - ef_sqrt.c \ - ef_rem_pio2.c \ - kf_cos.c \ - kf_sin.c \ - kf_rem_pio2.c \ - sf_copysign.c \ - sf_cos.c \ - sf_fabs.c \ - sf_floor.c \ - sf_scalbn.c \ - sf_sin.c \ - ef_log.c ALTOS_SRC = \ ao_boot_chain.c \ @@ -63,8 +48,6 @@ ALTOS_SRC = \ ao_timer.c \ ao_mutex.c \ ao_serial_stm.c \ - ao_ignite.c \ - ao_freq.c \ ao_dma_stm.c \ ao_spi_stm.c \ ao_storage.c \ @@ -72,8 +55,14 @@ ALTOS_SRC = \ ao_usb_stm.c \ ao_exti_stm.c \ ao_i2c_stm.c \ - ao_convert_volt.c \ - $(MATH_SRC) \ + ao_vga.c \ + ao_blt.c \ + ao_copy.c \ + ao_rect.c \ + ao_text.c \ + ao_line.c \ + ao_ps2.c \ + ao_console.c \ $(PROFILE) \ $(SAMPLE_PROFILE) \ $(STACK_GUARD) diff --git a/src/cortexelf-v1/ao_cortexelf.c b/src/cortexelf-v1/ao_cortexelf.c index 01c5165b..776530e0 100644 --- a/src/cortexelf-v1/ao_cortexelf.c +++ b/src/cortexelf-v1/ao_cortexelf.c @@ -22,6 +22,171 @@ #if HAS_STACK_GUARD #include #endif +#include +#include +#include + +struct ao_task ball_task; + +#define BALL_WIDTH 5 +#define BALL_HEIGHT 5 + +static int ball_x; +static int ball_y; +static int ball_dx, ball_dy; + +uint8_t ball_enable; + +void +ao_ball(void) +{ + ball_dx = 1; + ball_dy = 1; + ball_x = 0; + ball_y = 0; + for (;;) { + while (!ball_enable) + ao_sleep(&ball_enable); + for (;;) { + ao_line(&ao_vga_bitmap, + -100, -100, ball_x*2, ball_y*2, + 1, AO_XOR); + ao_text(&ao_vga_bitmap, + ball_x, ball_y - 10, + "Hello, Bdale!", + 1, AO_XOR); + ao_rect(&ao_vga_bitmap, + ball_x, ball_y, + BALL_WIDTH, + BALL_HEIGHT, + 1, + AO_XOR); + ao_delay(AO_MS_TO_TICKS(10)); + ao_rect(&ao_vga_bitmap, + ball_x, ball_y, + BALL_WIDTH, + BALL_HEIGHT, + 1, + AO_XOR); + ao_text(&ao_vga_bitmap, + ball_x, ball_y - 10, + "Hello, Bdale!", + 1, AO_XOR); + ao_line(&ao_vga_bitmap, + -100, -100, ball_x*2, ball_y*2, + 1, AO_XOR); + if (!ball_enable) + break; + ball_x += ball_dx; + ball_y += ball_dy; + if (ball_x + BALL_WIDTH > AO_VGA_WIDTH) { + ball_x = AO_VGA_WIDTH - BALL_WIDTH; + ball_dx = -ball_dx; + } + if (ball_x < 0) { + ball_x = -ball_x; + ball_dx = -ball_dx; + } + if (ball_y + BALL_HEIGHT > AO_VGA_HEIGHT) { + ball_y = AO_VGA_HEIGHT - BALL_HEIGHT; + ball_dy = -ball_dy; + } + if (ball_y < 0) { + ball_y = -ball_y; + ball_dy = -ball_dy; + } + } + } +} + +static void +ao_fb_init(void) +{ + ao_rect(&ao_vga_bitmap, + 0, 0, AO_VGA_WIDTH, AO_VGA_HEIGHT, + 1, AO_COPY); + + ao_rect(&ao_vga_bitmap, + 10, 10, 10, 10, + 0, AO_COPY); + + ao_rect(&ao_vga_bitmap, + AO_VGA_WIDTH - 20, 10, 10, 10, + 0, AO_COPY); + + ao_rect(&ao_vga_bitmap, + 10, AO_VGA_HEIGHT - 20, 10, 10, + 0, AO_COPY); + + ao_rect(&ao_vga_bitmap, + AO_VGA_WIDTH - 20, AO_VGA_HEIGHT - 20, 10, 10, + 0, AO_COPY); + + ao_text(&ao_vga_bitmap, + 20, 100, + "Hello, Bdale!", + 0, AO_COPY); + + ao_text(&ao_vga_bitmap, + 1, ao_font.ascent, + "UL", + 0, AO_COPY); + + ao_text(&ao_vga_bitmap, + 1, AO_VGA_HEIGHT - ao_font.descent, + "BL", + 0, AO_COPY); +} + +static void +ao_video_toggle(void) +{ + ao_cmd_decimal(); + if (ao_cmd_lex_i) + ao_fb_init(); + ao_vga_enable(ao_cmd_lex_i); +} + +static void +ao_ball_toggle(void) +{ + ao_cmd_decimal(); + ball_enable = ao_cmd_lex_i; + ao_wakeup(&ball_enable); +} + +static void +ao_ps2_read_keys(void) +{ + char c; + + for (;;) { + c = ao_ps2_getchar(); + printf("%02x %c\n", c, ' ' <= c && c < 0x7f ? c : '.'); + flush(); + if (c == ' ') + break; + } +} + +static void +ao_console_send(void) +{ + char c; + + while ((c = getchar()) != '~') { + ao_console_putchar(c); + flush(); + } +} + +__code struct ao_cmds ao_demo_cmds[] = { + { ao_video_toggle, "V\0Toggle video" }, + { ao_ball_toggle, "B\0Toggle ball" }, + { ao_ps2_read_keys, "K\0Read keys from keyboard" }, + { ao_console_send, "C\0Send data to console, end with ~" }, + { 0, NULL } +}; int main(void) @@ -40,12 +205,19 @@ main(void) ao_dma_init(); ao_exti_init(); + ao_ps2_init(); + ao_vga_init(); + ao_console_init(); + ao_cmd_init(); ao_usb_init(); ao_config_init(); + ao_add_task(&ball_task, ao_ball, "ball"); + ao_cmd_register(&ao_demo_cmds[0]); + ao_start_scheduler(); return 0; } diff --git a/src/cortexelf-v1/ao_pins.h b/src/cortexelf-v1/ao_pins.h index 2c960a6b..e486038a 100644 --- a/src/cortexelf-v1/ao_pins.h +++ b/src/cortexelf-v1/ao_pins.h @@ -44,6 +44,15 @@ #define AO_APB2_PRESCALER 2 #define AO_RCC_CFGR_PPRE2_DIV STM_RCC_CFGR_PPRE2_DIV_2 +/* Allow for non-maskable interrupts at priority 0 */ +#define AO_NONMASK_INTERRUPT 1 + +/* PS/2 keyboard connection */ +#define AO_PS2_CLOCK_PORT (&stm_gpiod) +#define AO_PS2_CLOCK_BIT 9 +#define AO_PS2_DATA_PORT (&stm_gpiod) +#define AO_PS2_DATA_BIT 8 + #define HAS_SERIAL_1 1 #define USE_SERIAL_1_STDIN 0 #define SERIAL_1_PB6_PB7 1 -- cgit v1.2.3 From 62b0228aed5191c8d769f9f34143a13036e210a7 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 2 Apr 2017 15:18:34 -0700 Subject: cortexelf-v1: Fix clock to drive VGA at 640/480. Add sdcard, remove others VGA requires the CPU to run at 24MHz. Signed-off-by: Keith Packard --- src/cortexelf-v1/Makefile | 4 +- src/cortexelf-v1/ao_cortexelf.c | 3 ++ src/cortexelf-v1/ao_pins.h | 99 ++++++++--------------------------------- 3 files changed, 22 insertions(+), 84 deletions(-) (limited to 'src') diff --git a/src/cortexelf-v1/Makefile b/src/cortexelf-v1/Makefile index e0fdc8fd..c74b0cce 100644 --- a/src/cortexelf-v1/Makefile +++ b/src/cortexelf-v1/Makefile @@ -42,7 +42,6 @@ ALTOS_SRC = \ ao_cmd.c \ ao_config.c \ ao_task.c \ - ao_led.c \ ao_stdio.c \ ao_panic.c \ ao_timer.c \ @@ -50,8 +49,6 @@ ALTOS_SRC = \ ao_serial_stm.c \ ao_dma_stm.c \ ao_spi_stm.c \ - ao_storage.c \ - ao_m25.c \ ao_usb_stm.c \ ao_exti_stm.c \ ao_i2c_stm.c \ @@ -63,6 +60,7 @@ ALTOS_SRC = \ ao_line.c \ ao_ps2.c \ ao_console.c \ + ao_sdcard.c \ $(PROFILE) \ $(SAMPLE_PROFILE) \ $(STACK_GUARD) diff --git a/src/cortexelf-v1/ao_cortexelf.c b/src/cortexelf-v1/ao_cortexelf.c index 776530e0..67062c85 100644 --- a/src/cortexelf-v1/ao_cortexelf.c +++ b/src/cortexelf-v1/ao_cortexelf.c @@ -25,6 +25,7 @@ #include #include #include +#include struct ao_task ball_task; @@ -205,6 +206,8 @@ main(void) ao_dma_init(); ao_exti_init(); + ao_sdcard_init(); + ao_ps2_init(); ao_vga_init(); ao_console_init(); diff --git a/src/cortexelf-v1/ao_pins.h b/src/cortexelf-v1/ao_pins.h index e486038a..91555cd4 100644 --- a/src/cortexelf-v1/ao_pins.h +++ b/src/cortexelf-v1/ao_pins.h @@ -28,21 +28,21 @@ #define AO_PLLMUL 12 #define AO_RCC_CFGR_PLLMUL (STM_RCC_CFGR_PLLMUL_12) -/* SYSCLK = 32MHz (no need to go faster than CPU) */ -#define AO_PLLDIV 3 -#define AO_RCC_CFGR_PLLDIV (STM_RCC_CFGR_PLLDIV_3) +/* SYSCLK = 24MHz */ +#define AO_PLLDIV 4 +#define AO_RCC_CFGR_PLLDIV (STM_RCC_CFGR_PLLDIV_4) -/* HCLK = 32MHz (CPU clock) */ +/* HCLK = 24MHz (CPU clock) */ #define AO_AHB_PRESCALER 1 #define AO_RCC_CFGR_HPRE_DIV STM_RCC_CFGR_HPRE_DIV_1 -/* Run APB1 at 16MHz (HCLK/2) */ -#define AO_APB1_PRESCALER 2 -#define AO_RCC_CFGR_PPRE1_DIV STM_RCC_CFGR_PPRE2_DIV_2 +/* Run APB1 at HCLK/1 */ +#define AO_APB1_PRESCALER 1 +#define AO_RCC_CFGR_PPRE1_DIV STM_RCC_CFGR_PPRE2_DIV_1 -/* Run APB2 at 16MHz (HCLK/2) */ -#define AO_APB2_PRESCALER 2 -#define AO_RCC_CFGR_PPRE2_DIV STM_RCC_CFGR_PPRE2_DIV_2 +/* Run APB2 at HCLK/1 */ +#define AO_APB2_PRESCALER 1 +#define AO_RCC_CFGR_PPRE2_DIV STM_RCC_CFGR_PPRE2_DIV_1 /* Allow for non-maskable interrupts at priority 0 */ #define AO_NONMASK_INTERRUPT 1 @@ -108,84 +108,21 @@ #define LOW_LEVEL_DEBUG 0 -#define LED_PORT_ENABLE STM_RCC_AHBENR_GPIOCEN -#define LED_PORT (&stm_gpioc) -#define LED_PIN_RED 0 -#define LED_PIN_GREEN 0 -#define AO_LED_RED (1 << LED_PIN_RED) -#define AO_LED_GREEN (1 << LED_PIN_GREEN) - -#define LEDS_AVAILABLE 0 - #define HAS_GPS 0 #define HAS_FLIGHT 0 #define HAS_ADC 0 #define HAS_ADC_TEMP 0 #define HAS_LOG 0 -/* - * Pressure sensor settings - */ -#define HAS_MS5607 0 -#define HAS_MS5611 0 -#define AO_MS5607_PRIVATE_PINS 0 -#define AO_MS5607_CS_PORT (&stm_gpioc) -#define AO_MS5607_CS_PIN 4 -#define AO_MS5607_CS_MASK (1 << AO_MS5607_CS) -#define AO_MS5607_MISO_PORT (&stm_gpioa) -#define AO_MS5607_MISO_PIN 6 -#define AO_MS5607_MISO_MASK (1 << AO_MS5607_MISO) -#define AO_MS5607_SPI_INDEX AO_SPI_1_PA5_PA6_PA7 - -/* - * SPI Flash memory - */ - -#define M25_MAX_CHIPS 0 -#define AO_M25_SPI_CS_PORT (&stm_gpiod) -#define AO_M25_SPI_CS_MASK (1 << 3) -#define AO_M25_SPI_BUS AO_SPI_2_PB13_PB14_PB15 - #define NUM_CMDS 16 -/* - * Monitor - */ - -#define HAS_MONITOR 0 -#define LEGACY_MONITOR 0 -#define HAS_MONITOR_PUT 0 -#define AO_MONITOR_LED 0 -#define HAS_RSSI 0 - -/* - * Profiling Viterbi decoding - */ - -#ifndef AO_PROFILE -#define AO_PROFILE 0 -#endif - -/* - * PWM output - */ - -#define NUM_PWM 0 -#define PWM_MAX 20000 -#define AO_PWM_TIMER stm_tim4 -#define AO_PWM_TIMER_ENABLE STM_RCC_APB1ENR_TIM4EN -#define AO_PWM_TIMER_SCALE 32 - -#define AO_PWM_0_GPIO (&stm_gpiod) -#define AO_PWM_0_PIN 12 - -#define AO_PWM_1_GPIO (&stm_gpiod) -#define AO_PWM_1_PIN 13 - -#define AO_PWM_2_GPIO (&stm_gpiod) -#define AO_PWM_2_PIN 14 - -#define AO_PWM_3_GPIO (&stm_gpiod) -#define AO_PWM_3_PIN 15 +/* SD card */ +#define AO_SDCARD_SPI_BUS AO_SPI_2_PD1_PD3_PD4 +#define AO_SDCARD_SPI_CS_PORT (&stm_gpiod) +#define AO_SDCARD_SPI_CS_PIN 2 +#define AO_SDCARD_SPI_PORT (&stm_gpiod) +#define AO_SDCARD_SPI_SCK_PIN 1 +#define AO_SDCARD_SPI_MISO_PIN 3 +#define AO_SDCARD_SPI_MOSI_PIN 4 #endif /* _AO_PINS_H_ */ -- cgit v1.2.3 From 7b031d5a86213364196b67f7e3f92865da8adbf9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 2 Apr 2017 15:28:45 -0700 Subject: cortexelf-v1: Hook up serial consoles for debugging This will make playing with serial ports easier for now. Signed-off-by: Keith Packard --- src/cortexelf-v1/ao_pins.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/cortexelf-v1/ao_pins.h b/src/cortexelf-v1/ao_pins.h index 91555cd4..bc8288cf 100644 --- a/src/cortexelf-v1/ao_pins.h +++ b/src/cortexelf-v1/ao_pins.h @@ -54,12 +54,12 @@ #define AO_PS2_DATA_BIT 8 #define HAS_SERIAL_1 1 -#define USE_SERIAL_1_STDIN 0 +#define USE_SERIAL_1_STDIN 1 #define SERIAL_1_PB6_PB7 1 #define SERIAL_1_PA9_PA10 0 #define HAS_SERIAL_2 1 -#define USE_SERIAL_2_STDIN 0 +#define USE_SERIAL_2_STDIN 1 #define SERIAL_2_PA2_PA3 0 #define SERIAL_2_PD5_PD6 1 -- cgit v1.2.3 From 54c76d48924fecc2aeabbc352c553822a87f9d19 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 2 Apr 2017 15:40:03 -0700 Subject: cortexelf-v1: Use new memory map to access all flash and ram. Add fat. Signed-off-by: Keith Packard --- src/cortexelf-v1/Makefile | 5 ++- src/cortexelf-v1/ao_cortexelf.c | 2 + src/stm/altos-512.ld | 98 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 src/stm/altos-512.ld (limited to 'src') diff --git a/src/cortexelf-v1/Makefile b/src/cortexelf-v1/Makefile index c74b0cce..02ef817e 100644 --- a/src/cortexelf-v1/Makefile +++ b/src/cortexelf-v1/Makefile @@ -4,6 +4,7 @@ # include ../stm/Makefile.defs +LDFLAGS=-L../stm -Wl,-Taltos-512.ld INC = \ ao.h \ @@ -61,6 +62,8 @@ ALTOS_SRC = \ ao_ps2.c \ ao_console.c \ ao_sdcard.c \ + ao_bufio.c \ + ao_fat.c \ $(PROFILE) \ $(SAMPLE_PROFILE) \ $(STACK_GUARD) @@ -80,7 +83,7 @@ OBJ=$(SRC:.c=.o) all: $(PROG) $(HEX) -$(PROG): Makefile $(OBJ) altos.ld +$(PROG): Makefile $(OBJ) altos-512.ld $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) ../altitude-pa.h: make-altitude-pa diff --git a/src/cortexelf-v1/ao_cortexelf.c b/src/cortexelf-v1/ao_cortexelf.c index 67062c85..0c6852d9 100644 --- a/src/cortexelf-v1/ao_cortexelf.c +++ b/src/cortexelf-v1/ao_cortexelf.c @@ -26,6 +26,7 @@ #include #include #include +#include struct ao_task ball_task; @@ -207,6 +208,7 @@ main(void) ao_exti_init(); ao_sdcard_init(); + ao_fat_init(); ao_ps2_init(); ao_vga_init(); diff --git a/src/stm/altos-512.ld b/src/stm/altos-512.ld new file mode 100644 index 00000000..78c41685 --- /dev/null +++ b/src/stm/altos-512.ld @@ -0,0 +1,98 @@ +/* + * Copyright © 2017 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +MEMORY { + rom (rx) : ORIGIN = 0x08001000, LENGTH = 508K + ram (!w) : ORIGIN = 0x20000000, LENGTH = 81408 + stack (!w) : ORIGIN = 0x20013e00, LENGTH = 512 +} + +INCLUDE registers.ld + +EXTERN (stm_interrupt_vector) + +SECTIONS { + /* + * Rom contents + */ + + .text ORIGIN(rom) : { + __text_start__ = .; + *(.interrupt) /* Interrupt vectors */ + + . = ORIGIN(rom) + 0x100; + + + /* Ick. What I want is to specify the + * addresses of some global constants so + * that I can find them across versions + * of the application. I can't figure out + * how to make gnu ld do that, so instead + * we just load the two files that include + * these defines in the right order here and + * expect things to 'just work'. Don't change + * the contents of those files, ok? + */ + ao_romconfig.o(.romconfig*) + ao_product.o(.romconfig*) + *(.text*) /* Executable code */ + *(.rodata*) /* Constants */ + + } > rom + + .ARM.exidx : { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > rom + __text_end__ = .; + + /* Boot data which must live at the start of ram so that + * the application and bootloader share the same addresses. + * This must be all uninitialized data + */ + .boot (NOLOAD) : { + __boot_start__ = .; + *(.boot) + . = ALIGN(4); + __boot_end__ = .; + } >ram + + /* Data -- relocated to RAM, but written to ROM + */ + .data : { + __data_start__ = .; + *(.data) /* initialized data */ + . = ALIGN(4); + __data_end__ = .; + } >ram AT>rom + + .bss : { + __bss_start__ = .; + *(.bss) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } >ram + + PROVIDE(end = .); + + PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack)); +} + +ENTRY(start); + + -- cgit v1.2.3 From 1f5f0638f283fbb784021873c649109d4ed0257c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 2 Apr 2017 15:53:17 -0700 Subject: cortexelf: Add lisp interpreter Signed-off-by: Keith Packard --- src/cortexelf-v1/Makefile | 25 ++++++++- src/cortexelf-v1/ao_cortexelf.c | 6 +++ src/cortexelf-v1/ao_lisp_os.h | 65 ++++++++++++++++++++++++ src/cortexelf-v1/ao_lisp_os_save.c | 53 +++++++++++++++++++ src/cortexelf-v1/cortexelf.ld | 101 +++++++++++++++++++++++++++++++++++++ 5 files changed, 248 insertions(+), 2 deletions(-) create mode 100644 src/cortexelf-v1/ao_lisp_os.h create mode 100644 src/cortexelf-v1/ao_lisp_os_save.c create mode 100644 src/cortexelf-v1/cortexelf.ld (limited to 'src') diff --git a/src/cortexelf-v1/Makefile b/src/cortexelf-v1/Makefile index 02ef817e..66f18045 100644 --- a/src/cortexelf-v1/Makefile +++ b/src/cortexelf-v1/Makefile @@ -4,7 +4,7 @@ # include ../stm/Makefile.defs -LDFLAGS=-L../stm -Wl,-Taltos-512.ld +LDFLAGS=-L../stm -Wl,-Tcortexelf.ld INC = \ ao.h \ @@ -25,6 +25,9 @@ INC = \ ao_draw_int.h \ ao_font.h \ ao_ps2.h \ + ao_lisp.h \ + ao_lisp_const.h \ + ao_lisp_os.h \ Makefile @@ -64,6 +67,24 @@ ALTOS_SRC = \ ao_sdcard.c \ ao_bufio.c \ ao_fat.c \ + ao_flash_stm.c \ + ao_lisp_lex.c \ + ao_lisp_mem.c \ + ao_lisp_cons.c \ + ao_lisp_eval.c \ + ao_lisp_string.c \ + ao_lisp_atom.c \ + ao_lisp_int.c \ + ao_lisp_poly.c \ + ao_lisp_builtin.c \ + ao_lisp_read.c \ + ao_lisp_rep.c \ + ao_lisp_frame.c \ + ao_lisp_error.c \ + ao_lisp_lambda.c \ + ao_lisp_save.c \ + ao_lisp_stack.c \ + ao_lisp_os_save.c \ $(PROFILE) \ $(SAMPLE_PROFILE) \ $(STACK_GUARD) @@ -83,7 +104,7 @@ OBJ=$(SRC:.c=.o) all: $(PROG) $(HEX) -$(PROG): Makefile $(OBJ) altos-512.ld +$(PROG): Makefile $(OBJ) cortexelf.ld $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) ../altitude-pa.h: make-altitude-pa diff --git a/src/cortexelf-v1/ao_cortexelf.c b/src/cortexelf-v1/ao_cortexelf.c index 0c6852d9..1dc0a4be 100644 --- a/src/cortexelf-v1/ao_cortexelf.c +++ b/src/cortexelf-v1/ao_cortexelf.c @@ -27,6 +27,7 @@ #include #include #include +#include struct ao_task ball_task; @@ -182,11 +183,16 @@ ao_console_send(void) } } +static void lisp_cmd() { + ao_lisp_read_eval_print(); +} + __code struct ao_cmds ao_demo_cmds[] = { { ao_video_toggle, "V\0Toggle video" }, { ao_ball_toggle, "B\0Toggle ball" }, { ao_ps2_read_keys, "K\0Read keys from keyboard" }, { ao_console_send, "C\0Send data to console, end with ~" }, + { lisp_cmd, "l\0Run lisp interpreter" }, { 0, NULL } }; diff --git a/src/cortexelf-v1/ao_lisp_os.h b/src/cortexelf-v1/ao_lisp_os.h new file mode 100644 index 00000000..d0c1f7b7 --- /dev/null +++ b/src/cortexelf-v1/ao_lisp_os.h @@ -0,0 +1,65 @@ +/* + * Copyright © 2016 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_LISP_OS_H_ +#define _AO_LISP_OS_H_ + +#include "ao.h" + +#define AO_LISP_POOL_TOTAL 16384 +#define AO_LISP_SAVE 1 + +static inline int +ao_lisp_getc() { + static uint8_t at_eol; + int c; + + if (at_eol) { + ao_cmd_readline(); + at_eol = 0; + } + c = ao_cmd_lex(); + if (c == '\n') + at_eol = 1; + return c; +} + +static inline void +ao_lisp_os_flush(void) +{ + flush(); +} + +static inline void +ao_lisp_abort(void) +{ + ao_panic(1); +} + +static inline void +ao_lisp_os_led(int led) +{ + (void) led; +} + +static inline void +ao_lisp_os_delay(int delay) +{ + ao_delay(AO_MS_TO_TICKS(delay)); +} + +#endif diff --git a/src/cortexelf-v1/ao_lisp_os_save.c b/src/cortexelf-v1/ao_lisp_os_save.c new file mode 100644 index 00000000..7c853990 --- /dev/null +++ b/src/cortexelf-v1/ao_lisp_os_save.c @@ -0,0 +1,53 @@ +/* + * Copyright © 2016 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include + +extern uint8_t __flash__[]; + +/* saved variables to rebuild the heap + + ao_lisp_atoms + ao_lisp_frame_global + */ + +int +ao_lisp_os_save(void) +{ + int i; + + for (i = 0; i < AO_LISP_POOL_TOTAL; i += 256) { + uint32_t *dst = (uint32_t *) (void *) &__flash__[i]; + uint32_t *src = (uint32_t *) (void *) &ao_lisp_pool[i]; + + ao_flash_page(dst, src); + } + return 1; +} + +int +ao_lisp_os_restore_save(struct ao_lisp_os_save *save, int offset) +{ + memcpy(save, &__flash__[offset], sizeof (struct ao_lisp_os_save)); + return 1; +} + +int +ao_lisp_os_restore(void) +{ + memcpy(ao_lisp_pool, __flash__, AO_LISP_POOL_TOTAL); + return 1; +} diff --git a/src/cortexelf-v1/cortexelf.ld b/src/cortexelf-v1/cortexelf.ld new file mode 100644 index 00000000..6ad2a679 --- /dev/null +++ b/src/cortexelf-v1/cortexelf.ld @@ -0,0 +1,101 @@ +/* + * Copyright © 2017 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +MEMORY { + rom (rx) : ORIGIN = 0x08001000, LENGTH = 492K + flash (r) : ORIGIN = 0x0807c000, LENGTH = 16K + ram (!w) : ORIGIN = 0x20000000, LENGTH = 81408 + stack (!w) : ORIGIN = 0x20013e00, LENGTH = 512 +} + +INCLUDE registers.ld + +EXTERN (stm_interrupt_vector) + +SECTIONS { + /* + * Rom contents + */ + + .text ORIGIN(rom) : { + __text_start__ = .; + *(.interrupt) /* Interrupt vectors */ + + . = ORIGIN(rom) + 0x100; + + + /* Ick. What I want is to specify the + * addresses of some global constants so + * that I can find them across versions + * of the application. I can't figure out + * how to make gnu ld do that, so instead + * we just load the two files that include + * these defines in the right order here and + * expect things to 'just work'. Don't change + * the contents of those files, ok? + */ + ao_romconfig.o(.romconfig*) + ao_product.o(.romconfig*) + *(.text*) /* Executable code */ + *(.rodata*) /* Constants */ + + } > rom + + .ARM.exidx : { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > rom + __text_end__ = .; + + /* Boot data which must live at the start of ram so that + * the application and bootloader share the same addresses. + * This must be all uninitialized data + */ + .boot (NOLOAD) : { + __boot_start__ = .; + *(.boot) + . = ALIGN(4); + __boot_end__ = .; + } >ram + + /* Data -- relocated to RAM, but written to ROM + */ + .data : { + __data_start__ = .; + *(.data) /* initialized data */ + . = ALIGN(4); + __data_end__ = .; + } >ram AT>rom + + .bss : { + __bss_start__ = .; + *(.bss) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } >ram + + PROVIDE(end = .); + + PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack)); + + __flash__ = ORIGIN(flash); +} + +ENTRY(start); + + -- cgit v1.2.3 From 3ce663875d69739cc2d43fcd88b22820cd9d6500 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 2 Apr 2017 15:56:17 -0700 Subject: stm: Use common flash wait loop instead of inlining Signed-off-by: Keith Packard --- src/stm/ao_flash_stm.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/stm/ao_flash_stm.c b/src/stm/ao_flash_stm.c index c1648421..38618bbe 100644 --- a/src/stm/ao_flash_stm.c +++ b/src/stm/ao_flash_stm.c @@ -74,11 +74,10 @@ static void __attribute__ ((section(".ramtext"),noinline)) _ao_flash_erase_page(uint32_t *page) { stm_flash.pecr |= (1 << STM_FLASH_PECR_ERASE) | (1 << STM_FLASH_PECR_PROG); - + *page = 0x00000000; - while (stm_flash.sr & (1 << STM_FLASH_SR_BSY)) - ; + ao_flash_wait_bsy(); } void @@ -101,9 +100,8 @@ _ao_flash_half_page(uint32_t *dst, uint32_t *src) stm_flash.pecr |= (1 << STM_FLASH_PECR_FPRG); stm_flash.pecr |= (1 << STM_FLASH_PECR_PROG); - - while (stm_flash.sr & (1 << STM_FLASH_SR_BSY)) - ; + + ao_flash_wait_bsy(); for (i = 0; i < 32; i++) { *dst++ = *src++; -- cgit v1.2.3 From 6fb817f218a69b28973b0d059d71809717b1e2d1 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 2 Apr 2017 16:17:33 -0700 Subject: lisp: Fix up lisp build so projects can get ao_lisp_const.h built as needed Signed-off-by: Keith Packard --- src/cortexelf-v1/Makefile | 6 ++++-- src/lisp/Makefile | 25 ++++--------------------- src/lisp/Makefile-inc | 22 ++++++++++++++++++++++ src/lisp/Makefile-lisp | 4 ++++ 4 files changed, 34 insertions(+), 23 deletions(-) create mode 100644 src/lisp/Makefile-inc create mode 100644 src/lisp/Makefile-lisp (limited to 'src') diff --git a/src/cortexelf-v1/Makefile b/src/cortexelf-v1/Makefile index 66f18045..cea75ddf 100644 --- a/src/cortexelf-v1/Makefile +++ b/src/cortexelf-v1/Makefile @@ -102,7 +102,7 @@ HEX=$(PROGNAME)-$(VERSION).ihx SRC=$(ALTOS_SRC) ao_cortexelf.c OBJ=$(SRC:.c=.o) -all: $(PROG) $(HEX) +all:: $(PROG) $(HEX) $(PROG): Makefile $(OBJ) cortexelf.ld $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) @@ -117,10 +117,12 @@ ao_product.h: ao-make-product.5c ../Version distclean: clean -clean: +clean:: rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx rm -f ao_product.h +include ../lisp/Makefile-lisp + install: uninstall: diff --git a/src/lisp/Makefile b/src/lisp/Makefile index dd5a0cb4..25796ec5 100644 --- a/src/lisp/Makefile +++ b/src/lisp/Makefile @@ -6,32 +6,15 @@ clean: ao_lisp_const.h: ao_lisp_const.lisp ao_lisp_make_const ./ao_lisp_make_const -o $@ ao_lisp_const.lisp -SRCS=\ - ao_lisp_make_const.c\ - ao_lisp_mem.c \ - ao_lisp_cons.c \ - ao_lisp_string.c \ - ao_lisp_atom.c \ - ao_lisp_int.c \ - ao_lisp_poly.c \ - ao_lisp_builtin.c \ - ao_lisp_read.c \ - ao_lisp_frame.c \ - ao_lisp_lambda.c \ - ao_lisp_eval.c \ - ao_lisp_rep.c \ - ao_lisp_save.c \ - ao_lisp_stack.c \ - ao_lisp_error.c +include Makefile-inc +SRCS=$(LISP_SRCS) + +HDRS=$(LISP_HDRS) OBJS=$(SRCS:.c=.o) CFLAGS=-DAO_LISP_MAKE_CONST -O0 -g -I. -Wall -Wextra -no-pie -HDRS=\ - ao_lisp.h \ - ao_lisp_os.h \ - ao_lisp_read.h ao_lisp_make_const: $(OBJS) $(CC) $(CFLAGS) -o $@ $(OBJS) diff --git a/src/lisp/Makefile-inc b/src/lisp/Makefile-inc new file mode 100644 index 00000000..126deeb0 --- /dev/null +++ b/src/lisp/Makefile-inc @@ -0,0 +1,22 @@ +LISP_SRCS=\ + ao_lisp_make_const.c\ + ao_lisp_mem.c \ + ao_lisp_cons.c \ + ao_lisp_string.c \ + ao_lisp_atom.c \ + ao_lisp_int.c \ + ao_lisp_poly.c \ + ao_lisp_builtin.c \ + ao_lisp_read.c \ + ao_lisp_frame.c \ + ao_lisp_lambda.c \ + ao_lisp_eval.c \ + ao_lisp_rep.c \ + ao_lisp_save.c \ + ao_lisp_stack.c \ + ao_lisp_error.c + +LISP_HDRS=\ + ao_lisp.h \ + ao_lisp_os.h \ + ao_lisp_read.h diff --git a/src/lisp/Makefile-lisp b/src/lisp/Makefile-lisp new file mode 100644 index 00000000..998c7673 --- /dev/null +++ b/src/lisp/Makefile-lisp @@ -0,0 +1,4 @@ +include ../lisp/Makefile-inc + +ao_lisp_const.h: $(LISP_SRCS) $(LISP_HDRS) + +cd ../lisp && make $@ -- cgit v1.2.3 From 8284d3639cd24e2fa0faf1e35e7276ba35a24f8f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 2 Apr 2017 16:22:28 -0700 Subject: cortexelf-v1: Add serialblather command. This reads from stdin and dumps it to both serial ports until you type ~ Signed-off-by: Keith Packard --- src/cortexelf-v1/ao_cortexelf.c | 12 ++++++++++++ src/cortexelf-v1/ao_pins.h | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/cortexelf-v1/ao_cortexelf.c b/src/cortexelf-v1/ao_cortexelf.c index 1dc0a4be..f9be59e8 100644 --- a/src/cortexelf-v1/ao_cortexelf.c +++ b/src/cortexelf-v1/ao_cortexelf.c @@ -187,11 +187,23 @@ static void lisp_cmd() { ao_lisp_read_eval_print(); } +static void +ao_serial_blather(void) +{ + char c; + + while ((c = getchar()) != '~') { + ao_serial1_putchar(c); + ao_serial2_putchar(c); + } +} + __code struct ao_cmds ao_demo_cmds[] = { { ao_video_toggle, "V\0Toggle video" }, { ao_ball_toggle, "B\0Toggle ball" }, { ao_ps2_read_keys, "K\0Read keys from keyboard" }, { ao_console_send, "C\0Send data to console, end with ~" }, + { ao_serial_blather, "S\0Blather on serial ports briefly" }, { lisp_cmd, "l\0Run lisp interpreter" }, { 0, NULL } }; diff --git a/src/cortexelf-v1/ao_pins.h b/src/cortexelf-v1/ao_pins.h index bc8288cf..e9c9deb3 100644 --- a/src/cortexelf-v1/ao_pins.h +++ b/src/cortexelf-v1/ao_pins.h @@ -38,7 +38,7 @@ /* Run APB1 at HCLK/1 */ #define AO_APB1_PRESCALER 1 -#define AO_RCC_CFGR_PPRE1_DIV STM_RCC_CFGR_PPRE2_DIV_1 +#define AO_RCC_CFGR_PPRE1_DIV STM_RCC_CFGR_PPRE1_DIV_1 /* Run APB2 at HCLK/1 */ #define AO_APB2_PRESCALER 1 -- cgit v1.2.3 From 1bc48b075f76bfef258f516549573429b24f284c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 2 Apr 2017 16:37:42 -0700 Subject: cortexelf-v1: Add buttons Signed-off-by: Keith Packard --- src/cortexelf-v1/Makefile | 2 ++ src/cortexelf-v1/ao_cortexelf.c | 20 ++++++++++++++++++++ src/cortexelf-v1/ao_pins.h | 24 ++++++++++++++++++++++++ 3 files changed, 46 insertions(+) (limited to 'src') diff --git a/src/cortexelf-v1/Makefile b/src/cortexelf-v1/Makefile index cea75ddf..f7c892bc 100644 --- a/src/cortexelf-v1/Makefile +++ b/src/cortexelf-v1/Makefile @@ -68,6 +68,8 @@ ALTOS_SRC = \ ao_bufio.c \ ao_fat.c \ ao_flash_stm.c \ + ao_button.c \ + ao_event.c \ ao_lisp_lex.c \ ao_lisp_mem.c \ ao_lisp_cons.c \ diff --git a/src/cortexelf-v1/ao_cortexelf.c b/src/cortexelf-v1/ao_cortexelf.c index f9be59e8..8be7ef15 100644 --- a/src/cortexelf-v1/ao_cortexelf.c +++ b/src/cortexelf-v1/ao_cortexelf.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include struct ao_task ball_task; @@ -208,6 +210,21 @@ __code struct ao_cmds ao_demo_cmds[] = { { 0, NULL } }; +static struct ao_task event_task; + +static void +ao_event_loop(void) +{ + for (;;) { + struct ao_event ev; + + ao_event_get(&ev); + printf("type %d uint %d tick %d value %d\n", + ev.type, ev.unit, ev.tick, ev.value); + flush(); + } +} + int main(void) { @@ -236,9 +253,12 @@ main(void) ao_usb_init(); + ao_button_init(); + ao_config_init(); ao_add_task(&ball_task, ao_ball, "ball"); + ao_add_task(&event_task, ao_event_loop, "events"); ao_cmd_register(&ao_demo_cmds[0]); ao_start_scheduler(); diff --git a/src/cortexelf-v1/ao_pins.h b/src/cortexelf-v1/ao_pins.h index e9c9deb3..d39f4022 100644 --- a/src/cortexelf-v1/ao_pins.h +++ b/src/cortexelf-v1/ao_pins.h @@ -125,4 +125,28 @@ #define AO_SDCARD_SPI_MISO_PIN 3 #define AO_SDCARD_SPI_MOSI_PIN 4 +/* Buttons */ + +#define AO_EVENT 1 + +#define AO_BUTTON_COUNT 4 +#define AO_BUTTON_MODE AO_EXTI_MODE_PULL_DOWN + +/* INPUT */ +#define AO_BUTTON_0_PORT (&stm_gpioc) +#define AO_BUTTON_0 8 + +/* MP */ +#define AO_BUTTON_1_PORT (&stm_gpioc) +#define AO_BUTTON_1 9 + +/* RUN */ +#define AO_BUTTON_2_PORT (&stm_gpioc) +#define AO_BUTTON_2 10 + +/* LOAD */ +#define AO_BUTTON_3_PORT (&stm_gpioc) +#define AO_BUTTON_3 11 + + #endif /* _AO_PINS_H_ */ -- cgit v1.2.3 From cc1b56faa88c75c9c86af89c77d7f1349573b7b0 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 2 Apr 2017 17:39:05 -0700 Subject: altos: Add AS1107 LED display driver Signed-off-by: Keith Packard --- src/drivers/ao_as1107.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++ src/drivers/ao_as1107.h | 59 ++++++++++++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 src/drivers/ao_as1107.c create mode 100644 src/drivers/ao_as1107.h (limited to 'src') diff --git a/src/drivers/ao_as1107.c b/src/drivers/ao_as1107.c new file mode 100644 index 00000000..0b83ab2c --- /dev/null +++ b/src/drivers/ao_as1107.c @@ -0,0 +1,102 @@ +/* + * Copyright © 2017 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include + +static uint8_t as1107_configured; +static uint8_t as1107_mutex; + +static void +ao_as1107_start(void) { + ao_spi_get_bit(AO_AS1107_CS_PORT, AO_AS1107_CS_PIN, AO_AS1107_CS, AO_AS1107_SPI_INDEX, AO_AS1107_SPI_SPEED); +} + +static void +ao_as1107_stop(void) { + ao_spi_put_bit(AO_AS1107_CS_PORT, AO_AS1107_CS_PIN, AO_AS1107_CS, AO_AS1107_SPI_INDEX); +} + +static void +_ao_as1107_cmd(uint8_t addr, uint8_t value) +{ + uint8_t packet[2] = { addr, value }; + + ao_as1107_start(); + ao_spi_send(packet, 2, AO_AS1107_SPI_INDEX); + ao_as1107_stop(); +} + +static void +_ao_as1107_setup(void) +{ + if (!as1107_configured) { + as1107_configured = 1; + _ao_as1107_cmd(AO_AS1107_SHUTDOWN, AO_AS1107_SHUTDOWN_SHUTDOWN_RESET); + _ao_as1107_cmd(AO_AS1107_DECODE_MODE, AO_AS1107_DECODE); + _ao_as1107_cmd(AO_AS1107_SCAN_LIMIT, AO_AS1107_NUM_DIGITS - 1); + _ao_as1107_cmd(AO_AS1107_FEATURE, + (0 << AO_AS1107_FEATURE_CLK_EN) | + (0 << AO_AS1107_FEATURE_REG_RES) | + (1 << AO_AS1107_FEATURE_DECODE_SEL) | + (1 << AO_AS1107_FEATURE_SPI_EN) | + (0 << AO_AS1107_FEATURE_BLINK_EN) | + (0 << AO_AS1107_FEATURE_BLINK_FREQ) | + (0 << AO_AS1107_FEATURE_SYNC) | + (0 << AO_AS1107_FEATURE_BLINK_START)); + } +} + +void +ao_as1107_write(uint8_t start, uint8_t count, uint8_t *values) +{ + uint8_t i; + ao_mutex_get(&as1107_mutex); + _ao_as1107_setup(); + for (i = 0; i < count; i++) + { + _ao_as1107_cmd(AO_AS1107_DIGIT(start + i), + values[i]); + } + ao_mutex_put(&as1107_mutex); +} + +void +ao_as1107_write_8(uint8_t start, uint8_t value) +{ + uint8_t values[2]; + + values[0] = (value >> 4); + values[1] = value & 0xf; + ao_as1107_write(start, 2, values); +} + +void +ao_as1107_write_16(uint8_t start, uint16_t value) +{ + uint8_t values[4]; + + values[0] = (value >> 12); + values[1] = (value >> 8) & 0xf; + values[2] = (value >> 4) & 0xf; + values[3] = (value) & 0xf; + ao_as1107_write(start, 4, values); +} + +void +ao_as1107_init(void) +{ + as1107_configured = 0; + ao_spi_init_cs(AO_AS1107_CS_PORT, (1 << AO_AS1107_CS_PIN)); +} diff --git a/src/drivers/ao_as1107.h b/src/drivers/ao_as1107.h new file mode 100644 index 00000000..a22b17db --- /dev/null +++ b/src/drivers/ao_as1107.h @@ -0,0 +1,59 @@ +/* + * Copyright © 2017 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _AO_AS1107_H_ +#define _AO_AS1107_H_ + +#define AO_AS1107_NO_OP 0x00 +#define AO_AS1107_DIGIT(n) (0x01 + (n)) +#define AO_AS1107_DECODE_MODE 0x09 +#define AO_AS1107_INTENSITY 0x0a +#define AO_AS1107_SCAN_LIMIT 0x0b +#define AO_AS1107_SHUTDOWN 0x0c +#define AO_AS1107_SHUTDOWN_SHUTDOWN_RESET 0x00 +#define AO_AS1107_SHUTDOWN_SHUTDOWN_NOP 0x80 +#define AO_AS1107_SHUTDOWN_NORMAL_RESET 0x01 +#define AO_AS1107_SHUTDOWN_NORMAL_NOP 0x81 + +#define AO_AS1107_FEATURE 0x0e +#define AO_AS1107_FEATURE_CLK_EN 0 /* external clock enable */ +#define AO_AS1107_FEATURE_REG_RES 1 +#define AO_AS1107_FEATURE_DECODE_SEL 2 /* select HEX decode */ +#define AO_AS1107_FEATURE_SPI_EN 3 +#define AO_AS1107_FEATURE_BLINK_EN 4 +#define AO_AS1107_FEATURE_BLINK_FREQ 5 +#define AO_AS1107_FEATURE_SYNC 6 +#define AO_AS1107_FEATURE_BLINK_START 7 +#define AO_AS1107_DISPLAY_TEST 0x0f + +void ao_as1107_init(void); + +void +ao_as1107_write(uint8_t start, uint8_t count, uint8_t *values); + +void +ao_as1107_write_8(uint8_t start, uint8_t value); + +void +ao_as1107_write_16(uint8_t start, uint16_t value); + +#ifndef AO_AS1107_DECODE +#error "must define AO_AS1107_DECODE" +#endif + +#ifndef AO_AS1107_NUM_DIGITS +#error "must define AO_AS1107_NUM_DIGITS" +#endif + +#endif /* _AO_AS1107_H_ */ -- cgit v1.2.3 From 17ec1c510ccc42bbc387940b5805f452697f78d6 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 2 Apr 2017 17:39:26 -0700 Subject: cortexelf-v1: Hook up AS1107 in test mode Provide a 'L' command to display values Signed-off-by: Keith Packard --- src/cortexelf-v1/Makefile | 1 + src/cortexelf-v1/ao_cortexelf.c | 19 +++++++++++++++++++ src/cortexelf-v1/ao_pins.h | 16 ++++++++++++++++ 3 files changed, 36 insertions(+) (limited to 'src') diff --git a/src/cortexelf-v1/Makefile b/src/cortexelf-v1/Makefile index f7c892bc..65f16c2c 100644 --- a/src/cortexelf-v1/Makefile +++ b/src/cortexelf-v1/Makefile @@ -56,6 +56,7 @@ ALTOS_SRC = \ ao_usb_stm.c \ ao_exti_stm.c \ ao_i2c_stm.c \ + ao_as1107.c \ ao_vga.c \ ao_blt.c \ ao_copy.c \ diff --git a/src/cortexelf-v1/ao_cortexelf.c b/src/cortexelf-v1/ao_cortexelf.c index 8be7ef15..77fbd0c0 100644 --- a/src/cortexelf-v1/ao_cortexelf.c +++ b/src/cortexelf-v1/ao_cortexelf.c @@ -30,6 +30,7 @@ #include #include #include +#include struct ao_task ball_task; @@ -200,6 +201,21 @@ ao_serial_blather(void) } } +static void +led_cmd(void) +{ + uint8_t start; + uint8_t value; + ao_cmd_decimal(); + + start = ao_cmd_lex_i; + ao_cmd_hex(); + value = ao_cmd_lex_i; + if (ao_cmd_status != ao_cmd_success) + return; + ao_as1107_write_8(start, value); +} + __code struct ao_cmds ao_demo_cmds[] = { { ao_video_toggle, "V\0Toggle video" }, { ao_ball_toggle, "B\0Toggle ball" }, @@ -207,6 +223,7 @@ __code struct ao_cmds ao_demo_cmds[] = { { ao_console_send, "C\0Send data to console, end with ~" }, { ao_serial_blather, "S\0Blather on serial ports briefly" }, { lisp_cmd, "l\0Run lisp interpreter" }, + { led_cmd, "L start value\0Show value (byte) at digit start" }, { 0, NULL } }; @@ -255,6 +272,8 @@ main(void) ao_button_init(); + ao_as1107_init(); + ao_config_init(); ao_add_task(&ball_task, ao_ball, "ball"); diff --git a/src/cortexelf-v1/ao_pins.h b/src/cortexelf-v1/ao_pins.h index d39f4022..9721c56d 100644 --- a/src/cortexelf-v1/ao_pins.h +++ b/src/cortexelf-v1/ao_pins.h @@ -148,5 +148,21 @@ #define AO_BUTTON_3_PORT (&stm_gpioc) #define AO_BUTTON_3 11 +/* AS1107 */ +#define AO_AS1107_NUM_DIGITS 8 + +/* Set the hex digits up for decode, leave the extra leds alone */ + +#define AO_AS1107_DECODE ((1 << 7) | \ + (1 << 6) | \ + (1 << 4) | \ + (1 << 3) | \ + (1 << 1) | \ + (1 << 0)) + +#define AO_AS1107_SPI_INDEX AO_SPI_2_PD1_PD3_PD4 +#define AO_AS1107_SPI_SPEED AO_SPI_SPEED_8MHz +#define AO_AS1107_CS_PORT (&stm_gpiod) +#define AO_AS1107_CS_PIN 0 #endif /* _AO_PINS_H_ */ -- cgit v1.2.3 From 09f8710eb320f37f20dda8c635497c2b505d25e2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 2 Apr 2017 19:30:57 -0700 Subject: altos: add button matrix driver Scans the matrix once per clock tick queuing events for changed keys. Signed-off-by: Keith Packard --- src/drivers/ao_event.h | 1 + src/drivers/ao_matrix.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++++ src/drivers/ao_matrix.h | 24 ++++++ src/stm/ao_arch_funcs.h | 8 +- 4 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 src/drivers/ao_matrix.c create mode 100644 src/drivers/ao_matrix.h (limited to 'src') diff --git a/src/drivers/ao_event.h b/src/drivers/ao_event.h index d1c69d81..d1df6eac 100644 --- a/src/drivers/ao_event.h +++ b/src/drivers/ao_event.h @@ -22,6 +22,7 @@ #define AO_EVENT_NONE 0 #define AO_EVENT_QUADRATURE 1 #define AO_EVENT_BUTTON 2 +#define AO_EVENT_KEY 3 struct ao_event { uint8_t type; diff --git a/src/drivers/ao_matrix.c b/src/drivers/ao_matrix.c new file mode 100644 index 00000000..e0f8ba75 --- /dev/null +++ b/src/drivers/ao_matrix.c @@ -0,0 +1,201 @@ +/* + * Copyright © 2017 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include + +#define row_port(q) AO_MATRIX_ROW_ ## q ## _PORT +#define row_bit(q) AO_MATRIX_ROW_ ## q ## _PIN +#define row_pin(q) AO_MATRIX_ROW_ ## q ## _PIN + +#define col_port(q) AO_MATRIX_COL_ ## q ## _PORT +#define col_bit(q) AO_MATRIX_COL_ ## q ## _PIN +#define col_pin(q) AO_MATRIX_COL_ ## q ## _PIN + +static void +_ao_matrix_drive_row(uint8_t row, uint8_t val) +{ + switch (row) { +#define drive(n) case n: ao_gpio_set(row_port(n), row_bit(n), row_pin(n), val); break + drive(0); +#if AO_MATRIX_ROWS > 1 + drive(1); +#endif +#if AO_MATRIX_ROWS > 2 + drive(2); +#endif +#if AO_MATRIX_ROWS > 3 + drive(3); +#endif +#if AO_MATRIX_ROWS > 4 + drive(4); +#endif +#if AO_MATRIX_ROWS > 5 + drive(5); +#endif +#if AO_MATRIX_ROWS > 6 + drive(6); +#endif +#if AO_MATRIX_ROWS > 7 + drive(7); +#endif + } +} + +static uint8_t +_ao_matrix_read_cols(void) +{ + uint8_t v = 0; +#define read(n) (v |= ao_gpio_get(col_port(n), col_bit(n), col_pin(n)) << n) + + read(0); +#if AO_MATRIX_ROWS > 1 + read(1); +#endif +#if AO_MATRIX_ROWS > 2 + read(2); +#endif +#if AO_MATRIX_ROWS > 3 + read(3); +#endif +#if AO_MATRIX_ROWS > 4 + read(4); +#endif +#if AO_MATRIX_ROWS > 5 + read(5); +#endif +#if AO_MATRIX_ROWS > 6 + read(6); +#endif +#if AO_MATRIX_ROWS > 7 + read(7); +#endif + return v; +} + +static uint8_t +_ao_matrix_read(uint8_t row) { + uint8_t state; + _ao_matrix_drive_row(row, 1); + state = _ao_matrix_read_cols(); + _ao_matrix_drive_row(row, 0); + return state; +} + +#define AO_MATRIX_DEBOUNCE_INTERVAL AO_MS_TO_TICKS(50) + +static uint8_t ao_matrix_keymap[AO_MATRIX_ROWS][AO_MATRIX_COLS] = AO_MATRIX_KEYCODES; + +static uint8_t ao_matrix_state[AO_MATRIX_ROWS]; +static AO_TICK_TYPE ao_matrix_tick[AO_MATRIX_ROWS]; + +static void +_ao_matrix_poll_one(uint8_t row) { + uint8_t state = _ao_matrix_read(row); + + if (state != ao_matrix_state[row]) { + AO_TICK_TYPE now = ao_time(); + + if ((now - ao_matrix_tick[row]) >= AO_MATRIX_DEBOUNCE_INTERVAL) { + uint8_t col; + uint8_t changes = state ^ ao_matrix_state[row]; + + for (col = 0; col < AO_MATRIX_COLS; col++) { + if (changes & (1 << col)) { + ao_event_put_isr(AO_EVENT_KEY, + ao_matrix_keymap[row][col], + ((state >> col) & 1) == 0); + } + } + ao_matrix_state[row] = state; + } + ao_matrix_tick[row] = now; + } +} + +void +ao_matrix_poll(void) +{ + uint8_t row; + + for (row = 0; row < AO_MATRIX_ROWS; row++) + _ao_matrix_poll_one(row); +} + +#define init_row(b) do { \ + ao_enable_output(row_port(b), row_bit(b), row_pin(v), 1); \ + ao_gpio_set_output_mode(row_port(b), row_bit(b), row_pin(b), AO_OUTPUT_OPEN_DRAIN); \ + } while (0) + +#define init_col(b) do { \ + ao_enable_input(col_port(b), col_bit(b), AO_EXTI_MODE_PULL_UP); \ + } while(0) + +void +ao_matrix_init(void) +{ + uint8_t row; + + init_row(0); +#if AO_MATRIX_ROWS > 1 + init_row(1); +#endif +#if AO_MATRIX_ROWS > 2 + init_row(2); +#endif +#if AO_MATRIX_ROWS > 3 + init_row(3); +#endif +#if AO_MATRIX_ROWS > 4 + init_row(4); +#endif +#if AO_MATRIX_ROWS > 5 + init_row(5); +#endif +#if AO_MATRIX_ROWS > 6 + init_row(6); +#endif +#if AO_MATRIX_ROWS > 7 + init_row(7); +#endif + + init_col(0); +#if AO_MATRIX_COLS > 1 + init_col(1); +#endif +#if AO_MATRIX_COLS > 2 + init_col(2); +#endif +#if AO_MATRIX_COLS > 3 + init_col(3); +#endif +#if AO_MATRIX_COLS > 4 + init_col(4); +#endif +#if AO_MATRIX_COLS > 5 + init_col(5); +#endif +#if AO_MATRIX_COLS > 6 + init_col(6); +#endif +#if AO_MATRIX_COLS > 7 + init_col(7); +#endif + for (row = 0; row < AO_MATRIX_ROWS; row++) { + ao_matrix_state[row] = _ao_matrix_read(row); + ao_matrix_tick[row] = ao_time(); + } +} diff --git a/src/drivers/ao_matrix.h b/src/drivers/ao_matrix.h new file mode 100644 index 00000000..ab5a1c51 --- /dev/null +++ b/src/drivers/ao_matrix.h @@ -0,0 +1,24 @@ +/* + * Copyright © 2017 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _AO_MATRIX_H_ +#define _AO_MATRIX_H_ + +void +ao_matrix_poll(void); + +void +ao_matrix_init(void); + +#endif /* _AO_MATRIX_H_ */ diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index 88097406..b294c379 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -211,6 +211,12 @@ ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t s stm_moder_set(port, bit, STM_MODER_OUTPUT);\ } while (0) +#define AO_OUTPUT_PUSH_PULL STM_OTYPER_PUSH_PULL +#define AO_OUTPUT_OPEN_DRAIN STM_OTYPER_OPEN_DRAIN + +#define ao_gpio_set_output_mode(port,bit,pin,mode) \ + stm_otyper_set(port, pin, mode) + #define ao_gpio_set_mode(port,bit,mode) do { \ if (mode == AO_EXTI_MODE_PULL_UP) \ stm_pupdr_set(port, bit, STM_PUPDR_PULL_UP); \ @@ -219,7 +225,7 @@ ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t s else \ stm_pupdr_set(port, bit, STM_PUPDR_NONE); \ } while (0) - + #define ao_enable_input(port,bit,mode) do { \ ao_enable_port(port); \ stm_moder_set(port, bit, STM_MODER_INPUT); \ -- cgit v1.2.3 From 79215de60d3e11b4abd1ecd2fa9575a323b76754 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 2 Apr 2017 19:31:45 -0700 Subject: altos: Allow buttons to be high when pressed rather than low Signed-off-by: Keith Packard --- src/drivers/ao_button.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/drivers/ao_button.c b/src/drivers/ao_button.c index 725ac45a..07e92c67 100644 --- a/src/drivers/ao_button.c +++ b/src/drivers/ao_button.c @@ -39,8 +39,16 @@ static struct ao_button_state ao_button_state[AO_BUTTON_COUNT]; #define bit(q) AO_BUTTON_ ## q #define pin(q) AO_BUTTON_ ## q ## _PIN +#ifndef AO_BUTTON_INVERTED +#define AO_BUTTON_INVERTED 1 +#endif + +#if AO_BUTTON_INVERTED /* pins are inverted */ #define ao_button_value(b) !ao_gpio_get(port(b), bit(b), pin(b)) +#else +#define ao_button_value(b) ao_gpio_get(port(b), bit(b), pin(b)) +#endif static uint8_t _ao_button_get(uint8_t b) -- cgit v1.2.3 From 8c1478b55f5dbe9711b31a34d4f5e3563f1f42d2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 2 Apr 2017 19:32:17 -0700 Subject: cortexelf-v1: Hook up hex keypad using matrix input driver Signed-off-by: Keith Packard --- src/cortexelf-v1/Makefile | 1 + src/cortexelf-v1/ao_pins.h | 53 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 48 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/cortexelf-v1/Makefile b/src/cortexelf-v1/Makefile index 65f16c2c..b491c2e4 100644 --- a/src/cortexelf-v1/Makefile +++ b/src/cortexelf-v1/Makefile @@ -57,6 +57,7 @@ ALTOS_SRC = \ ao_exti_stm.c \ ao_i2c_stm.c \ ao_as1107.c \ + ao_matrix.c \ ao_vga.c \ ao_blt.c \ ao_copy.c \ diff --git a/src/cortexelf-v1/ao_pins.h b/src/cortexelf-v1/ao_pins.h index 9721c56d..034c2d5a 100644 --- a/src/cortexelf-v1/ao_pins.h +++ b/src/cortexelf-v1/ao_pins.h @@ -127,10 +127,11 @@ /* Buttons */ -#define AO_EVENT 1 +#define AO_EVENT 1 #define AO_BUTTON_COUNT 4 #define AO_BUTTON_MODE AO_EXTI_MODE_PULL_DOWN +#define AO_BUTTON_INVERTED 0 /* INPUT */ #define AO_BUTTON_0_PORT (&stm_gpioc) @@ -153,11 +154,11 @@ /* Set the hex digits up for decode, leave the extra leds alone */ -#define AO_AS1107_DECODE ((1 << 7) | \ - (1 << 6) | \ - (1 << 4) | \ - (1 << 3) | \ - (1 << 1) | \ +#define AO_AS1107_DECODE ((1 << 7) | \ + (1 << 6) | \ + (1 << 4) | \ + (1 << 3) | \ + (1 << 1) | \ (1 << 0)) #define AO_AS1107_SPI_INDEX AO_SPI_2_PD1_PD3_PD4 @@ -165,4 +166,44 @@ #define AO_AS1107_CS_PORT (&stm_gpiod) #define AO_AS1107_CS_PIN 0 +/* Hex keypad */ + +#define AO_MATRIX_ROWS 4 +#define AO_MATRIX_COLS 4 + +#define AO_MATRIX_KEYCODES { \ + { 0x0, 0x1, 0x2, 0x3 }, \ + { 0x4, 0x5, 0x6, 0x7 }, \ + { 0x8, 0x9, 0xa, 0xb }, \ + { 0xc, 0xd, 0xe, 0xf } \ + } + +#include + +#define AO_TIMER_HOOK ao_matrix_poll() + +#define AO_MATRIX_ROW_0_PORT (&stm_gpioc) +#define AO_MATRIX_ROW_0_PIN 4 + +#define AO_MATRIX_ROW_1_PORT (&stm_gpioc) +#define AO_MATRIX_ROW_1_PIN 1 + +#define AO_MATRIX_ROW_2_PORT (&stm_gpioc) +#define AO_MATRIX_ROW_2_PIN 7 + +#define AO_MATRIX_ROW_3_PORT (&stm_gpioc) +#define AO_MATRIX_ROW_3_PIN 0 + +#define AO_MATRIX_COL_0_PORT (&stm_gpioc) +#define AO_MATRIX_COL_0_PIN 2 + +#define AO_MATRIX_COL_1_PORT (&stm_gpioc) +#define AO_MATRIX_COL_1_PIN 3 + +#define AO_MATRIX_COL_2_PORT (&stm_gpioc) +#define AO_MATRIX_COL_2_PIN 5 + +#define AO_MATRIX_COL_3_PORT (&stm_gpioc) +#define AO_MATRIX_COL_3_PIN 6 + #endif /* _AO_PINS_H_ */ -- cgit v1.2.3 From 5bb9cf38c84663713c178f54b684d40b6c00b11d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 2 Apr 2017 20:33:49 -0700 Subject: cortexelf-v1: Add bit flipping array generator Someone hooked up the data lines between the systems backwards, so we get to swizzle the bits in software. Signed-off-by: Keith Packard --- src/cortexelf-v1/Makefile | 7 +++++-- src/cortexelf-v1/ao_flip_bits.5c | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 src/cortexelf-v1/ao_flip_bits.5c (limited to 'src') diff --git a/src/cortexelf-v1/Makefile b/src/cortexelf-v1/Makefile index b491c2e4..77598dda 100644 --- a/src/cortexelf-v1/Makefile +++ b/src/cortexelf-v1/Makefile @@ -28,9 +28,9 @@ INC = \ ao_lisp.h \ ao_lisp_const.h \ ao_lisp_os.h \ + ao_flip_bits.h \ Makefile - #PROFILE=ao_profile.c #PROFILE_DEF=-DAO_PROFILE=1 @@ -123,7 +123,10 @@ distclean: clean clean:: rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx - rm -f ao_product.h + rm -f ao_product.h ao_flip_bits.h + +ao_flip_bits.h: ao_flip_bits.5c + nickle ao_flip_bits.5c > $@ include ../lisp/Makefile-lisp diff --git a/src/cortexelf-v1/ao_flip_bits.5c b/src/cortexelf-v1/ao_flip_bits.5c new file mode 100644 index 00000000..26900893 --- /dev/null +++ b/src/cortexelf-v1/ao_flip_bits.5c @@ -0,0 +1,19 @@ +#!/usr/bin/nickle + +int flip_bits(int a) +{ + int result = 0; + for (int pos = 0; pos < 8; pos++) + if ((a & (1 << pos)) != 0) + result |= (1 << (7 - pos)); + return result; +} + +printf ("static uint8_t ao_flip_bits[256] = {\n"); + +for (int i = 0; i < 256; i++) { + printf (" 0x%02x,", flip_bits(i)); + if ((i & 0xf) == 0xf) + printf("\n"); +} +printf("};\n"); -- cgit v1.2.3 From 47004dfe8ee8c8b31085b066d3d0fd5142fd49da Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 3 Apr 2017 09:36:00 -0700 Subject: cortexelf-v1: doodling with 1802 bits Just some random ideas about how to manage the 1802 Signed-off-by: Keith Packard --- src/cortexelf-v1/Makefile | 1 + src/cortexelf-v1/ao_1802.c | 170 +++++++++++++++++++++++++++++++++++++++++++++ src/cortexelf-v1/ao_1802.h | 34 +++++++++ 3 files changed, 205 insertions(+) create mode 100644 src/cortexelf-v1/ao_1802.c create mode 100644 src/cortexelf-v1/ao_1802.h (limited to 'src') diff --git a/src/cortexelf-v1/Makefile b/src/cortexelf-v1/Makefile index 77598dda..d7157521 100644 --- a/src/cortexelf-v1/Makefile +++ b/src/cortexelf-v1/Makefile @@ -72,6 +72,7 @@ ALTOS_SRC = \ ao_flash_stm.c \ ao_button.c \ ao_event.c \ + ao_1802.c \ ao_lisp_lex.c \ ao_lisp_mem.c \ ao_lisp_cons.c \ diff --git a/src/cortexelf-v1/ao_1802.c b/src/cortexelf-v1/ao_1802.c new file mode 100644 index 00000000..55e778df --- /dev/null +++ b/src/cortexelf-v1/ao_1802.c @@ -0,0 +1,170 @@ +/* + * Copyright © 2017 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include + +/* Signals muxed between 1802 and STM */ +uint8_t MRD, TPB, TPA, MWR; + +/* Decoded address driven by TPA/TPB signals */ +uint16_t ADDRESS; + +/* Decoded data, driven by TPB signal */ +uint8_t DATA; + +/* Mux control */ +#define MUX_1802 0 +#define MUX_STM 1 + +uint8_t MUX_CONTROL; + +/* Signals driven by 1802 only */ +uint8_t WAIT, CLEAR, Q, SC, N; +uint8_t DMA_IN, DMA_OUT, INTERRUPT; +uint8_t EF; + +static uint8_t ma_stm; + +uint8_t +MA(void) { + if (MUX_CONTROL == MUX_1802) + return (ao_gpio_get_all(MA_PORT) >> MA_SHIFT) & 0xff; + else + return ma_stm; +} + +static void +MA_set(uint8_t ma) { + ao_gpio_set_mask(MA_PORT, ((uint16_t) ma) << MA_SHIFT, 0xff << MA_SHIFT); + ma_stm = ma; +} + +static uint8_t data_stm; + +static uint8_t +DATA_get(void) { + if (MUX_CONTROL == MUX_1802) + return ao_flip_bits[(ao_gpio_get_all(DATA_PORT) >> DATA_SHIFT) & 0xff]; + else + return data_stm; +} + +static void +DATA_set(uint8_t data) { + ao_gpio_set_mask(DATA_PORT, ((uint16_t) ao_flip_bits[data]) << DATA_SHIFT, 0xff << DATA_SHIFT); + data_stm = data; +} + +static uint8_t +N_get(void) { + return (ao_gpio_get_all(N_PORT) >> N_SHIFT) & 0x7; +} + +static uint8_t +EF_get(void) { + return (ao_gpio_get_all(EF_PORT) >> EF_SHIFT) & 0xf; +} + +static uint8_t +Q_get(void) { + return ao_gpio_get(Q_PORT, Q_BIT, Q_PIN); +} + +static uint8_t +SC_get(void) { + static const uint8_t flip_sc[4] = { 0, 2, 1, 3 }; + return flip_sc[(ao_gpio_get_all(SC_PORT) >> SC_SHIFT) & 3]; +} + +void +mrd(uint8_t value) { MRD = value; } + +void +mwr(uint8_t value) { MWR = value; } + +void +tpb(uint8_t value) { + TPB = value; + + /* Latch low address and data on rising edge of TPB */ + if (TPB) { + ADDRESS = (ADDRESS & 0xff00) | MA(); + DATA = DATA_get(); + N = N_get(); + ao_wakeup(&ADDRESS); + } +} + +void +tpa(uint8_t value) { + TPA = value; + + /* Latch high address on rising edge of TPA */ + if (TPA) { + ADDRESS = (ADDRESS & 0x00ff) | ((uint16_t) MA() << 8); + SC = SC_get(); + if (SC == SC_EXECUTE) + EF = EF_get(); + ao_wakeup(&ADDRESS); + } +} + +#define ao_1802_in(port, bit, callback) do { \ + ao_enable_input(port, bit, 0); \ + ao_exti_enable(port, bit); \ + ao_exti_set_callback(port, bit, callback); \ + (*callback)(); \ + } while (0) + +static void mrd_isr(void) { mrd(ao_gpio_get(MRD_PORT, MRD_BIT, MRD_PIN)); } +static void mwr_isr(void) { mwr(ao_gpio_get(MWR_PORT, MWR_BIT, MWR_PIN)); } +static void tpb_isr(void) { tpb(ao_gpio_get(TPB_PORT, TPB_BIT, TPB_PIN)); } +static void tpa_isr(void) { tpa(ao_gpio_get(TPA_PORT, TPA_BIT, TPA_PIN)); } +static void q_isr(void) { Q = Q_get(); } + +static void +ao_set_1802(void) +{ + ao_gpio_set(MUX_PORT, MUX_BIT, MUX_PIN, 0); + ao_1802_in(MRD_PORT, MRD_BIT, mrd_isr); + ao_1802_in(MWR_PORT, MWR_BIT, mwr_isr); + ao_1802_in(TPB_PORT, TPB_BIT, tpb_isr); + ao_1802_in(TPA_PORT, TPA_BIT, tpa_isr); + MUX_CONTROL = MUX_1802; +} + +static void +ao_set_arm(void) +{ + ao_enable_output(MRD_PORT, MRD_BIT, MRD_PIN, 1); + ao_enable_output(MWR_PORT, MWR_BIT, MWR_PIN, 1); + ao_enable_output(TPB_PORT, TPB_BIT, TPB_PIN, 0); + ao_enable_output(TPA_PORT, TPA_BIT, TPA_PIN, 0); + ao_gpio_set(MUX_PORT, MUX_BIT, MUX_PIN, 1); + MUX_CONTROL = MUX_STM; +} + +void +ao_1802_control_init(void) +{ + ao_set_1802(); + + ao_1802_in(Q_PORT, Q_BIT, q_isr); + (void) MA_set; + (void) DATA_set; + (void) ao_set_arm; +} diff --git a/src/cortexelf-v1/ao_1802.h b/src/cortexelf-v1/ao_1802.h new file mode 100644 index 00000000..daa49f66 --- /dev/null +++ b/src/cortexelf-v1/ao_1802.h @@ -0,0 +1,34 @@ +/* + * Copyright © 2017 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _AO_1802_H_ +#define _AO_1802_H_ + +/* Signals muxed between 1802 and STM */ +extern uint8_t MRD, TPB, TPA, MWR; + +/* Decoded address driven by TPA/TPB signals */ +extern uint16_t ADDRESS; + +/* Decoded data, driven by TPB signal */ +extern uint8_t DATA; + +extern uint8_t SC; + +#define SC_FETCH 0 +#define SC_EXECUTE 1 +#define SC_DMA 2 +#define SC_INTERRUPT 3 + +#endif /* _AO_1802_H_ */ -- cgit v1.2.3 From 89c8e0299504e66fc416a778055958cff467e008 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 3 Apr 2017 11:36:52 -0700 Subject: cortexelf-v1: Make bit flipping array constant Signed-off-by: Keith Packard --- src/cortexelf-v1/ao_flip_bits.5c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cortexelf-v1/ao_flip_bits.5c b/src/cortexelf-v1/ao_flip_bits.5c index 26900893..055d5299 100644 --- a/src/cortexelf-v1/ao_flip_bits.5c +++ b/src/cortexelf-v1/ao_flip_bits.5c @@ -9,7 +9,7 @@ int flip_bits(int a) return result; } -printf ("static uint8_t ao_flip_bits[256] = {\n"); +printf ("static const uint8_t ao_flip_bits[256] = {\n"); for (int i = 0; i < 256; i++) { printf (" 0x%02x,", flip_bits(i)); -- cgit v1.2.3 From 0197157a295d848bac65cf7f4457dd5a99af24e3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 3 Apr 2017 11:37:21 -0700 Subject: stm: Add a few more GPIO functions to make dealing with the 1802 easier ao_gpio_set_mask and ao_gpio_get_all Signed-off-by: Keith Packard --- src/stm/ao_arch_funcs.h | 3 +++ src/stm/stm32l.h | 6 ++++++ 2 files changed, 9 insertions(+) (limited to 'src') diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index b294c379..15741505 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -202,8 +202,11 @@ ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t s #define ao_gpio_set_bits(port, bits) stm_gpio_set_bits(port, bits) +#define ao_gpio_set_mask(port, bits, mask) stm_gpio_set_mask(port, bits, mask) + #define ao_gpio_clr_bits(port, bits) stm_gpio_clr_bits(port, bits); +#define ao_gpio_get_all(port) stm_gpio_get_all(port) #define ao_enable_output(port,bit,pin,v) do { \ ao_enable_port(port); \ diff --git a/src/stm/stm32l.h b/src/stm/stm32l.h index a20efa8a..4f966e3e 100644 --- a/src/stm/stm32l.h +++ b/src/stm/stm32l.h @@ -167,6 +167,12 @@ stm_gpio_set(struct stm_gpio *gpio, int pin, uint8_t value) { gpio->bsrr = ((uint32_t) (value ^ 1) << (pin + 16)) | ((uint32_t) value << pin); } +static inline void +stm_gpio_set_mask(struct stm_gpio *gpio, uint16_t bits, uint16_t mask) { + /* Use the bit set/reset register to do this atomically */ + gpio->bsrr = ((uint32_t) (~bits & mask) << 16) | ((uint32_t) (bits & mask)); +} + static inline void stm_gpio_set_bits(struct stm_gpio *gpio, uint16_t bits) { gpio->bsrr = bits; -- cgit v1.2.3 From 280eefc8f86e90e742c536a074d7284cce03af15 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 3 Apr 2017 11:41:51 -0700 Subject: cortexelf-v1: Add pin definitions for 1802 connections Signed-off-by: Keith Packard --- src/cortexelf-v1/ao_pins.h | 49 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'src') diff --git a/src/cortexelf-v1/ao_pins.h b/src/cortexelf-v1/ao_pins.h index 034c2d5a..d580ce3d 100644 --- a/src/cortexelf-v1/ao_pins.h +++ b/src/cortexelf-v1/ao_pins.h @@ -206,4 +206,53 @@ #define AO_MATRIX_COL_3_PORT (&stm_gpioc) #define AO_MATRIX_COL_3_PIN 6 +/* 1802 connections */ +#define MA_PORT (&stm_gpioe) +#define MA_SHIFT 0 + +#define DATA_PORT (&stm_gpioe) +#define DATA_SHIFT 8 + +#define MRD_PORT (&stm_gpiob) +#define MRD_BIT 15 + +#define MWR_PORT (&stm_gpioa) +#define MWR_BIT 3 + +#define TPB_PORT (&stm_gpioa) +#define TPB_BIT 7 + +#define TPA_PORT (&stm_gpioa) +#define TPA_BIT 6 + +#define MUX_PORT (&stm_gpiob) +#define MUX_BIT 1 + +#define WAIT_PORT (&stm_gpioa) +#define WAIT_PIN 4 + +#define CLEAR_PORT (&stm_gpioa) +#define CLEAR_PIN 10 + +#define Q_PORT (&stm_gpiob) +#define Q_BIT 12 + +#define SC_PORT (&stm_gpiob) +#define SC_SHIFT 13 + +#define N_PORT (&stm_gpiod) +#define N_SHIFT 13 + +#define DMA_IN_PORT (&stm_gpioa) +#define DMA_IN_PIN 0 + +#define DMA_OUT_PORT (&stm_gpioa) +#define DMA_OUT_PIN 9 + +#define INTERRUPT_PORT (&stm_gpioa) +#define INTERRUPT_PIN 2 + +#define EF_PORT (&stm_gpiob) +#define EF_SHIFT 8 + #endif /* _AO_PINS_H_ */ -- cgit v1.2.3 From 920b70fd5f6b78461c7ebae6b1e6490a0e050bc2 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 4 Apr 2017 15:59:56 -0700 Subject: altos: Define CC115L spi speed in each product Different SoCs have different SPI speeds available; have each product specify the speed to use instead of trying to use 4Mhz everywhere. Signed-off-by: Keith Packard --- src/drivers/ao_cc115l.c | 2 +- src/telegps-v0.1/ao_pins.h | 1 + src/telegps-v0.3/ao_pins.h | 1 + src/telegps-v1.0/ao_pins.h | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/drivers/ao_cc115l.c b/src/drivers/ao_cc115l.c index a67071d2..c1c21e0d 100644 --- a/src/drivers/ao_cc115l.c +++ b/src/drivers/ao_cc115l.c @@ -39,7 +39,7 @@ static uint8_t ao_radio_abort; /* radio operation should abort */ #define FOSC 26000000 -#define ao_radio_select() ao_spi_get_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS,AO_SPI_SPEED_6MHz) +#define ao_radio_select() ao_spi_get_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS,AO_CC115L_SPI_SPEED) #define ao_radio_deselect() ao_spi_put_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS) #define ao_radio_spi_send(d,l) ao_spi_send((d), (l), AO_CC115L_SPI_BUS) #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC115L_SPI_BUS) diff --git a/src/telegps-v0.1/ao_pins.h b/src/telegps-v0.1/ao_pins.h index 96e8cfd7..0b610cac 100644 --- a/src/telegps-v0.1/ao_pins.h +++ b/src/telegps-v0.1/ao_pins.h @@ -148,6 +148,7 @@ #define AO_CC115L_SPI_CS_PIN 12 #define AO_CC115L_SPI_BUS AO_SPI_2_PB13_PB14_PB15 #define AO_CC115L_SPI stm_spi2 +#define AO_CC115L_SPI_SPEED AO_SPI_SPEED_4MHz #define AO_CC115L_FIFO_INT_GPIO_IOCFG CC115L_IOCFG2 #define AO_CC115L_FIFO_INT_PORT (&stm_gpioa) diff --git a/src/telegps-v0.3/ao_pins.h b/src/telegps-v0.3/ao_pins.h index 9c650cc4..28ae30a4 100644 --- a/src/telegps-v0.3/ao_pins.h +++ b/src/telegps-v0.3/ao_pins.h @@ -95,6 +95,7 @@ #define AO_CC115L_SPI_CS_PORT 0 #define AO_CC115L_SPI_CS_PIN 3 #define AO_CC115L_SPI_BUS 0 +#define AO_CC115L_SPI_SPEED AO_SPI_SPEED_6MHz #define AO_CC115L_FIFO_INT_GPIO_IOCFG CC115L_IOCFG2 #define AO_CC115L_FIFO_INT_PORT 0 diff --git a/src/telegps-v1.0/ao_pins.h b/src/telegps-v1.0/ao_pins.h index 19774f63..9672ab03 100644 --- a/src/telegps-v1.0/ao_pins.h +++ b/src/telegps-v1.0/ao_pins.h @@ -97,6 +97,7 @@ #define AO_CC115L_SPI_CS_PORT 0 #define AO_CC115L_SPI_CS_PIN 3 #define AO_CC115L_SPI_BUS 0 +#define AO_CC115L_SPI_SPEED AO_SPI_SPEED_6MHz #define AO_CC115L_FIFO_INT_GPIO_IOCFG CC115L_IOCFG2 #define AO_CC115L_FIFO_INT_PORT 0 -- cgit v1.2.3 From d4ff161e89d852c07934704ea2cbea20a48259a7 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 4 Apr 2017 16:00:56 -0700 Subject: telegps-v0.1: Hack up for SDCARD debugging Disable everything not SDCARD related for debugging. Signed-off-by: Keith Packard --- src/telegps-v0.1/ao_pins.h | 4 ++++ src/telegps-v0.1/ao_telegps.c | 12 ++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/telegps-v0.1/ao_pins.h b/src/telegps-v0.1/ao_pins.h index 0b610cac..5afc9498 100644 --- a/src/telegps-v0.1/ao_pins.h +++ b/src/telegps-v0.1/ao_pins.h @@ -184,4 +184,8 @@ #define AO_SDCARD_SPI_CS_PIN 4 #define AO_SDCARD_SPI stm_spi1 +#define SDCARD_DEBUG 1 +#define SDCARD_WARN 1 +#define SDCARD_TRACE 1 + #endif /* _AO_PINS_H_ */ diff --git a/src/telegps-v0.1/ao_telegps.c b/src/telegps-v0.1/ao_telegps.c index eb8ab72d..f734d90f 100644 --- a/src/telegps-v0.1/ao_telegps.c +++ b/src/telegps-v0.1/ao_telegps.c @@ -49,16 +49,16 @@ main(void) ao_cmd_init(); ao_usb_init(); - ao_radio_init(); +// ao_radio_init(); ao_fat_init(); - ao_gps_init(); - ao_gps_report_mega_init(); +// ao_gps_init(); +// ao_gps_report_mega_init(); - ao_telemetry_init(); - ao_telemetry_set_interval(AO_SEC_TO_TICKS(1)); - ao_rdf_set(1); +// ao_telemetry_init(); +// ao_telemetry_set_interval(AO_SEC_TO_TICKS(1)); +// ao_rdf_set(1); #if HAS_SAMPLE_PROFILE ao_sample_profile_init(); -- cgit v1.2.3 From 4eced9224f40e48d7057352b3424c18025f43f25 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 4 Apr 2017 16:02:46 -0700 Subject: altos: Disable FAT commands unless requested This are debugging commands; don't provide them unless requested Signed-off-by: Keith Packard --- src/drivers/ao_fat.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/drivers/ao_fat.c b/src/drivers/ao_fat.c index fb8eecff..43e7df23 100644 --- a/src/drivers/ao_fat.c +++ b/src/drivers/ao_fat.c @@ -1615,7 +1615,7 @@ ao_fat_hexdump_cmd(void) ao_cmd_status = ao_cmd_syntax_error; return; } - + fd = ao_fat_open(name, AO_FAT_OPEN_READ); if (fd < 0) { printf ("Open failed: %d\n", fd); @@ -1649,5 +1649,7 @@ void ao_fat_init(void) { ao_bufio_init(); +#if FAT_COMMANDS ao_cmd_register(&ao_fat_cmds[0]); +#endif } -- cgit v1.2.3 From 71e430bb39fc97e543778f7bc1f1bef554ba8b75 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 4 Apr 2017 16:03:36 -0700 Subject: altos: Allow programs to enable SDCARD debugging if desired Provides for per-application control over SDCARD debugging Signed-off-by: Keith Packard --- src/drivers/ao_sdcard.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/drivers/ao_sdcard.c b/src/drivers/ao_sdcard.c index 4b17c5e3..45454000 100644 --- a/src/drivers/ao_sdcard.c +++ b/src/drivers/ao_sdcard.c @@ -38,13 +38,19 @@ extern uint8_t ao_radio_mutex; #define ao_sdcard_deselect() ao_gpio_set(AO_SDCARD_SPI_CS_PORT,AO_SDCARD_SPI_CS_PIN,AO_SDCARD_SPI_CS,1) /* Include SD card commands */ +#ifndef SDCARD_DEBUG #define SDCARD_DEBUG 0 +#endif /* Spew SD tracing */ +#ifndef SDCARD_TRACE #define SDCARD_TRACE 0 +#endif /* Emit error and warning messages */ +#ifndef SDCARD_WARN #define SDCARD_WARN 0 +#endif static uint8_t initialized; static uint8_t present; -- cgit v1.2.3 From 301b724d2169f4ac46d921f518455c783e1dd894 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 4 Apr 2017 16:04:25 -0700 Subject: stm: Add more mask-based GPIO controls Lets cortexelf do more things with groups of pins, rather than one pin at a time. Signed-off-by: Keith Packard --- src/stm/ao_arch_funcs.h | 79 ++++++++++++++++++++++++++++++++++++++----------- src/stm/stm32l.h | 53 +++++++++++++++++++++++++++++---- 2 files changed, 109 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index 15741505..522059bc 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -214,6 +214,12 @@ ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t s stm_moder_set(port, bit, STM_MODER_OUTPUT);\ } while (0) +#define ao_enable_output_mask(port,bits,mask) do { \ + ao_enable_port(port); \ + ao_gpio_set_mask(port, bits, mask); \ + ao_set_output_mask(port, mask); \ + } while (0) + #define AO_OUTPUT_PUSH_PULL STM_OTYPER_PUSH_PULL #define AO_OUTPUT_OPEN_DRAIN STM_OTYPER_OPEN_DRAIN @@ -229,35 +235,72 @@ ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t s stm_pupdr_set(port, bit, STM_PUPDR_NONE); \ } while (0) +#define ao_gpio_set_mode_mask(port,mask,mode) do { \ + if (mode == AO_EXTI_MODE_PULL_UP) \ + stm_pupdr_set_mask(port, mask, STM_PUPDR_PULL_UP); \ + else if (mode == AO_EXTI_MODE_PULL_DOWN) \ + stm_pupdr_set_mask(port, mask, STM_PUPDR_PULL_DOWN); \ + else \ + stm_pupdr_set_mask(port, mask, STM_PUPDR_NONE); \ + } while (0) + +#define ao_set_input(port, bit) do { \ + stm_moder_set(port, bit, STM_MODER_INPUT); \ + } while (0) + +#define ao_set_output(port, bit, pin, v) do { \ + ao_gpio_set(port, bit, pin, v); \ + stm_moder_set(port, bit, STM_MODER_OUTPUT); \ + } while (0) + +#define ao_set_output_mask(port, mask) do { \ + stm_moder_set_mask(port, mask, STM_MODER_OUTPUT); \ + } while (0) + +#define ao_set_input_mask(port, mask) do { \ + stm_moder_set_mask(port, mask, STM_MODER_INPUT); \ + } while (0) + #define ao_enable_input(port,bit,mode) do { \ ao_enable_port(port); \ - stm_moder_set(port, bit, STM_MODER_INPUT); \ + ao_set_input(port, bit); \ ao_gpio_set_mode(port, bit, mode); \ } while (0) -#define ao_enable_cs(port,bit) do { \ +#define ao_enable_input_mask(port,mask,mode) do { \ + ao_enable_port(port); \ + ao_gpio_set_mode_mask(port, mask, mode); \ + ao_set_input_mask(port, mask); \ + } while (0) + +#define _ao_enable_cs(port, bit) do { \ stm_gpio_set((port), bit, 1); \ stm_moder_set((port), bit, STM_MODER_OUTPUT); \ } while (0) +#define ao_enable_cs(port,bit) do { \ + ao_enable_port(port); \ + _ao_enable_cs(port, bit); \ + } while (0) + #define ao_spi_init_cs(port, mask) do { \ ao_enable_port(port); \ - if ((mask) & 0x0001) ao_enable_cs(port, 0); \ - if ((mask) & 0x0002) ao_enable_cs(port, 1); \ - if ((mask) & 0x0004) ao_enable_cs(port, 2); \ - if ((mask) & 0x0008) ao_enable_cs(port, 3); \ - if ((mask) & 0x0010) ao_enable_cs(port, 4); \ - if ((mask) & 0x0020) ao_enable_cs(port, 5); \ - if ((mask) & 0x0040) ao_enable_cs(port, 6); \ - if ((mask) & 0x0080) ao_enable_cs(port, 7); \ - if ((mask) & 0x0100) ao_enable_cs(port, 8); \ - if ((mask) & 0x0200) ao_enable_cs(port, 9); \ - if ((mask) & 0x0400) ao_enable_cs(port, 10);\ - if ((mask) & 0x0800) ao_enable_cs(port, 11);\ - if ((mask) & 0x1000) ao_enable_cs(port, 12);\ - if ((mask) & 0x2000) ao_enable_cs(port, 13);\ - if ((mask) & 0x4000) ao_enable_cs(port, 14);\ - if ((mask) & 0x8000) ao_enable_cs(port, 15);\ + if ((mask) & 0x0001) _ao_enable_cs(port, 0); \ + if ((mask) & 0x0002) _ao_enable_cs(port, 1); \ + if ((mask) & 0x0004) _ao_enable_cs(port, 2); \ + if ((mask) & 0x0008) _ao_enable_cs(port, 3); \ + if ((mask) & 0x0010) _ao_enable_cs(port, 4); \ + if ((mask) & 0x0020) _ao_enable_cs(port, 5); \ + if ((mask) & 0x0040) _ao_enable_cs(port, 6); \ + if ((mask) & 0x0080) _ao_enable_cs(port, 7); \ + if ((mask) & 0x0100) _ao_enable_cs(port, 8); \ + if ((mask) & 0x0200) _ao_enable_cs(port, 9); \ + if ((mask) & 0x0400) _ao_enable_cs(port, 10);\ + if ((mask) & 0x0800) _ao_enable_cs(port, 11);\ + if ((mask) & 0x1000) _ao_enable_cs(port, 12);\ + if ((mask) & 0x2000) _ao_enable_cs(port, 13);\ + if ((mask) & 0x4000) _ao_enable_cs(port, 14);\ + if ((mask) & 0x8000) _ao_enable_cs(port, 15);\ } while (0) /* ao_dma_stm.c diff --git a/src/stm/stm32l.h b/src/stm/stm32l.h index 4f966e3e..201f4f36 100644 --- a/src/stm/stm32l.h +++ b/src/stm/stm32l.h @@ -52,7 +52,32 @@ stm_moder_set(struct stm_gpio *gpio, int pin, vuint32_t value) { ~(STM_MODER_MASK << STM_MODER_SHIFT(pin))) | value << STM_MODER_SHIFT(pin)); } - + +static inline uint32_t +stm_spread_mask(uint16_t mask) { + uint32_t m = mask; + + /* 0000000000000000mmmmmmmmmmmmmmmm */ + m = (m & 0xff) | ((m & 0xff00) << 8); + /* 00000000mmmmmmmm00000000mmmmmmmm */ + m = (m & 0x000f000f) | ((m & 0x00f000f0) << 4); + /* 0000mmmm0000mmmm0000mmmm0000mmmm */ + m = (m & 0x03030303) | ((m & 0x0c0c0c0c) << 2); + /* 00mm00mm00mm00mm00mm00mm00mm00mm */ + m = (m & 0x11111111) | ((m & 0x22222222) << 2); + /* 0m0m0m0m0m0m0m0m0m0m0m0m0m0m0m0m */ + return m; +} + +static inline void +stm_moder_set_mask(struct stm_gpio *gpio, uint16_t mask, uint32_t value) { + uint32_t bits32 = stm_spread_mask(mask); + uint32_t mask32 = 3 * bits32; + uint32_t value32 = (value & 3) * bits32; + + gpio->moder = ((gpio->moder & ~mask32) | value32); +} + static inline uint32_t stm_moder_get(struct stm_gpio *gpio, int pin) { return (gpio->moder >> STM_MODER_SHIFT(pin)) & STM_MODER_MASK; @@ -69,7 +94,7 @@ stm_otyper_set(struct stm_gpio *gpio, int pin, vuint32_t value) { ~(STM_OTYPER_MASK << STM_OTYPER_SHIFT(pin))) | value << STM_OTYPER_SHIFT(pin)); } - + static inline uint32_t stm_otyper_get(struct stm_gpio *gpio, int pin) { return (gpio->otyper >> STM_OTYPER_SHIFT(pin)) & STM_OTYPER_MASK; @@ -83,12 +108,21 @@ stm_otyper_get(struct stm_gpio *gpio, int pin) { #define STM_OSPEEDR_40MHz 3 static inline void -stm_ospeedr_set(struct stm_gpio *gpio, int pin, vuint32_t value) { +stm_ospeedr_set(struct stm_gpio *gpio, int pin, uint32_t value) { gpio->ospeedr = ((gpio->ospeedr & ~(STM_OSPEEDR_MASK << STM_OSPEEDR_SHIFT(pin))) | value << STM_OSPEEDR_SHIFT(pin)); } - + +static inline void +stm_ospeedr_set_mask(struct stm_gpio *gpio, uint16_t mask, uint32_t value) { + uint32_t bits32 = stm_spread_mask(mask); + uint32_t mask32 = 3 * bits32; + uint32_t value32 = (value & 3) * bits32; + + gpio->ospeedr = ((gpio->ospeedr & ~mask32) | value32); +} + static inline uint32_t stm_ospeedr_get(struct stm_gpio *gpio, int pin) { return (gpio->ospeedr >> STM_OSPEEDR_SHIFT(pin)) & STM_OSPEEDR_MASK; @@ -107,7 +141,16 @@ stm_pupdr_set(struct stm_gpio *gpio, int pin, uint32_t value) { ~(STM_PUPDR_MASK << STM_PUPDR_SHIFT(pin))) | value << STM_PUPDR_SHIFT(pin)); } - + +static inline void +stm_pupdr_set_mask(struct stm_gpio *gpio, uint16_t mask, uint32_t value) { + uint32_t bits32 = stm_spread_mask(mask); + uint32_t mask32 = 3 * bits32; + uint32_t value32 = (value & 3) * bits32; + + gpio->pupdr = (gpio->pupdr & ~mask32) | value32; +} + static inline uint32_t stm_pupdr_get(struct stm_gpio *gpio, int pin) { return (gpio->pupdr >> STM_PUPDR_SHIFT(pin)) & STM_PUPDR_MASK; -- cgit v1.2.3 From 86d5119f19b5f3131d224982e011fd233b48aa22 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 4 Apr 2017 16:05:15 -0700 Subject: cortexelf-v1: More 1802 noodling Add code to track the address and data displays, change how 1802 pin tracking works Signed-off-by: Keith Packard --- src/cortexelf-v1/Makefile | 1 + src/cortexelf-v1/ao_1802.c | 342 ++++++++++++++++++++++++++++----------- src/cortexelf-v1/ao_1802.h | 103 +++++++++++- src/cortexelf-v1/ao_cortexelf.c | 6 + src/cortexelf-v1/ao_flip_bits.5c | 23 +-- src/cortexelf-v1/ao_hex.c | 36 +++++ src/cortexelf-v1/ao_hex.h | 21 +++ src/cortexelf-v1/ao_pins.h | 47 +++--- 8 files changed, 453 insertions(+), 126 deletions(-) create mode 100644 src/cortexelf-v1/ao_hex.c create mode 100644 src/cortexelf-v1/ao_hex.h (limited to 'src') diff --git a/src/cortexelf-v1/Makefile b/src/cortexelf-v1/Makefile index d7157521..8cc6ce31 100644 --- a/src/cortexelf-v1/Makefile +++ b/src/cortexelf-v1/Makefile @@ -73,6 +73,7 @@ ALTOS_SRC = \ ao_button.c \ ao_event.c \ ao_1802.c \ + ao_hex.c \ ao_lisp_lex.c \ ao_lisp_mem.c \ ao_lisp_cons.c \ diff --git a/src/cortexelf-v1/ao_1802.c b/src/cortexelf-v1/ao_1802.c index 55e778df..b7e11637 100644 --- a/src/cortexelf-v1/ao_1802.c +++ b/src/cortexelf-v1/ao_1802.c @@ -17,9 +17,6 @@ #include #include -/* Signals muxed between 1802 and STM */ -uint8_t MRD, TPB, TPA, MWR; - /* Decoded address driven by TPA/TPB signals */ uint16_t ADDRESS; @@ -27,144 +24,305 @@ uint16_t ADDRESS; uint8_t DATA; /* Mux control */ -#define MUX_1802 0 -#define MUX_STM 1 +#define _MUX_1802 0 +#define _MUX_STM 1 uint8_t MUX_CONTROL; -/* Signals driven by 1802 only */ -uint8_t WAIT, CLEAR, Q, SC, N; -uint8_t DMA_IN, DMA_OUT, INTERRUPT; -uint8_t EF; +/* Signals muxed between 1802 and STM */ +uint8_t +MRD(void) { + return ao_gpio_get(MRD_PORT, MRD_BIT, MRD_PIN); +} -static uint8_t ma_stm; +void +MRD_set(uint8_t value) { + ao_gpio_set(MRD_PORT, MRD_BIT, MRD_PIN, value); +} uint8_t -MA(void) { - if (MUX_CONTROL == MUX_1802) - return (ao_gpio_get_all(MA_PORT) >> MA_SHIFT) & 0xff; - else - return ma_stm; +MWR(void) { + return ao_gpio_get(MWR_PORT, MWR_BIT, MWR_PIN); +} + +void +MWR_set(uint8_t value) { + ao_gpio_set(MWR_PORT, MWR_BIT, MWR_PIN, value); } static void -MA_set(uint8_t ma) { - ao_gpio_set_mask(MA_PORT, ((uint16_t) ma) << MA_SHIFT, 0xff << MA_SHIFT); - ma_stm = ma; +TPA_rising(void) +{ + ADDRESS = (ADDRESS & 0x00ff) | ((uint16_t) MA() << 8); + ao_wakeup(&ADDRESS); } -static uint8_t data_stm; +uint8_t +TPA(void) { + return ao_gpio_get(TPA_PORT, TPA_BIT, TPA_PIN); +} -static uint8_t -DATA_get(void) { - if (MUX_CONTROL == MUX_1802) - return ao_flip_bits[(ao_gpio_get_all(DATA_PORT) >> DATA_SHIFT) & 0xff]; - else - return data_stm; +void +TPA_set(uint8_t tpa) { + ao_gpio_set(TPA_PORT, TPA_BIT, TPA_PIN, tpa); + if (tpa) + TPA_rising(); +} + +static void +TPB_rising(void) +{ + ADDRESS = (ADDRESS & 0xff00) | MA(); + ao_wakeup(&ADDRESS); } static void -DATA_set(uint8_t data) { - ao_gpio_set_mask(DATA_PORT, ((uint16_t) ao_flip_bits[data]) << DATA_SHIFT, 0xff << DATA_SHIFT); - data_stm = data; +TPB_falling(void) +{ + DATA = BUS(); + ao_wakeup(&ADDRESS); } -static uint8_t -N_get(void) { - return (ao_gpio_get_all(N_PORT) >> N_SHIFT) & 0x7; +uint8_t +TPB(void) { + return ao_gpio_get(TPB_PORT, TPB_BIT, TPB_PIN); } -static uint8_t -EF_get(void) { - return (ao_gpio_get_all(EF_PORT) >> EF_SHIFT) & 0xf; +void +TPB_set(uint8_t tpb) { + ao_gpio_set(TPB_PORT, TPB_BIT, TPB_PIN, tpb); + if (tpb) + TPB_rising(); + else + TPB_falling(); } -static uint8_t -Q_get(void) { +uint8_t +MA(void) { + return (ao_gpio_get_all(MA_PORT) >> MA_SHIFT) & MA_MASK; +} + +void +MA_set(uint8_t ma) { + ao_gpio_set_mask(MA_PORT, ((uint16_t) ma) << MA_SHIFT, MA_MASK << MA_SHIFT); +} + +/* Tri-state data bus */ + +uint8_t +BUS(void) { + return ao_flip_bits_8[(ao_gpio_get_all(BUS_PORT) >> BUS_SHIFT) & BUS_MASK]; +} + +void +BUS_set(uint8_t bus) { + ao_gpio_set_mask(BUS_PORT, ao_flip_bits_8[bus] << BUS_SHIFT, BUS_MASK << BUS_SHIFT); +} + +void +BUS_stm(void) +{ + ao_set_output_mask(BUS_PORT, BUS_MASK << BUS_SHIFT); +} + +void +BUS_1802(void) +{ + ao_set_input_mask(BUS_PORT, BUS_MASK << BUS_SHIFT); +} + +/* Pins controlled by 1802 */ +uint8_t +SC(void) { + return ao_flip_bits_2[(ao_gpio_get_all(SC_PORT) >> SC_SHIFT) & SC_MASK]; +} + +uint8_t +Q(void) { return ao_gpio_get(Q_PORT, Q_BIT, Q_PIN); } -static uint8_t -SC_get(void) { - static const uint8_t flip_sc[4] = { 0, 2, 1, 3 }; - return flip_sc[(ao_gpio_get_all(SC_PORT) >> SC_SHIFT) & 3]; +uint8_t +N(void) { + return (ao_gpio_get_all(N_PORT) >> N_SHIFT) & N_MASK; +} + +/* Pins controlled by STM */ +uint8_t +EF(void) { + return (ao_gpio_get_all(EF_PORT) >> EF_SHIFT) & EF_MASK; } void -mrd(uint8_t value) { MRD = value; } +EF_set(uint8_t ef) { + ao_gpio_set_mask(EF_PORT, ef << EF_SHIFT, EF_MASK << EF_SHIFT); +} + +uint8_t +DMA_IN(void) { + return ao_gpio_get(DMA_IN_PORT, DMA_IN_BIT, DMA_IN_PIN); +} void -mwr(uint8_t value) { MWR = value; } +DMA_IN_set(uint8_t dma_in) { + ao_gpio_set(DMA_IN_PORT, DMA_IN_BIT, DMA_IN_PIN, dma_in); +} + +uint8_t +DMA_OUT(void) { + return ao_gpio_get(DMA_OUT_PORT, DMA_OUT_BIT, DMA_OUT_PIN); +} void -tpb(uint8_t value) { - TPB = value; +DMA_OUT_set(uint8_t dma_out) { + ao_gpio_set(DMA_OUT_PORT, DMA_OUT_BIT, DMA_OUT_PIN, dma_out); +} - /* Latch low address and data on rising edge of TPB */ - if (TPB) { - ADDRESS = (ADDRESS & 0xff00) | MA(); - DATA = DATA_get(); - N = N_get(); - ao_wakeup(&ADDRESS); - } +uint8_t +INT(void) { + return ao_gpio_get(INT_PORT, INT_BIT, INT_PIN); } void -tpa(uint8_t value) { - TPA = value; +INT_set(uint8_t dma_out) { + ao_gpio_set(INT_PORT, INT_BIT, INT_PIN, dma_out); +} + +uint8_t +CLEAR(void) { + return ao_gpio_get(CLEAR_PORT, CLEAR_BIT, CLEAR_PIN); +} + +void +CLEAR_set(uint8_t dma_out) { + ao_gpio_set(CLEAR_PORT, CLEAR_BIT, CLEAR_PIN, dma_out); +} +uint8_t +WAIT(void) { + return ao_gpio_get(WAIT_PORT, WAIT_BIT, WAIT_PIN); +} + +void +WAIT_set(uint8_t dma_out) { + ao_gpio_set(WAIT_PORT, WAIT_BIT, WAIT_PIN, dma_out); +} + +void +tpb_isr(void) { + /* Latch low address and data on rising edge of TPB */ + if (TPB()) + TPB_rising(); + else + TPB_falling(); +} + +void +tpa_isr(void) { /* Latch high address on rising edge of TPA */ - if (TPA) { - ADDRESS = (ADDRESS & 0x00ff) | ((uint16_t) MA() << 8); - SC = SC_get(); - if (SC == SC_EXECUTE) - EF = EF_get(); - ao_wakeup(&ADDRESS); - } + if (TPA()) + TPA_rising(); } -#define ao_1802_in(port, bit, callback) do { \ - ao_enable_input(port, bit, 0); \ - ao_exti_enable(port, bit); \ - ao_exti_set_callback(port, bit, callback); \ - (*callback)(); \ +#define ao_1802_in(port, bit, mode) do { \ + ao_gpio_set_mode(port, bit, mode); \ + ao_set_input(port, bit); \ + } while (0) + +#define ao_1802_in_isr(port, bit, mode) do { \ + ao_gpio_set_mode(port, bit, mode); \ + ao_set_input(port, bit); \ + ao_exti_enable(port, bit); \ } while (0) -static void mrd_isr(void) { mrd(ao_gpio_get(MRD_PORT, MRD_BIT, MRD_PIN)); } -static void mwr_isr(void) { mwr(ao_gpio_get(MWR_PORT, MWR_BIT, MWR_PIN)); } -static void tpb_isr(void) { tpb(ao_gpio_get(TPB_PORT, TPB_BIT, TPB_PIN)); } -static void tpa_isr(void) { tpa(ao_gpio_get(TPA_PORT, TPA_BIT, TPA_PIN)); } -static void q_isr(void) { Q = Q_get(); } +#define ao_1802_out_isr(port, bit) do { \ + ao_exti_disable(port, bit); \ + ao_set_output(port, bit); \ + } while (0) -static void -ao_set_1802(void) +void +MUX_1802(void) { - ao_gpio_set(MUX_PORT, MUX_BIT, MUX_PIN, 0); - ao_1802_in(MRD_PORT, MRD_BIT, mrd_isr); - ao_1802_in(MWR_PORT, MWR_BIT, mwr_isr); - ao_1802_in(TPB_PORT, TPB_BIT, tpb_isr); - ao_1802_in(TPA_PORT, TPA_BIT, tpa_isr); - MUX_CONTROL = MUX_1802; + if (MUX_CONTROL != _MUX_1802) { + /* Set pins to input, but pulled to idle value */ + ao_1802_in(MRD_PORT, MRD_BIT, AO_EXTI_MODE_PULL_UP); + ao_1802_in(MWR_PORT, MWR_BIT, AO_EXTI_MODE_PULL_UP); + ao_1802_in_isr(TPB_PORT, TPB_BIT, AO_EXTI_MODE_PULL_DOWN); + ao_1802_in_isr(TPA_PORT, TPA_BIT, AO_EXTI_MODE_PULL_DOWN); + ao_set_input_mask(MA_PORT, MA_MASK << MA_SHIFT); + + ao_gpio_set(MUX_PORT, MUX_BIT, MUX_PIN, 0); + + /* Now change the pins to eliminate the pull up/down */ + ao_gpio_set_mode(MRD_PORT, MRD_BIT, 0); + ao_gpio_set_mode(MWR_PORT, MWR_BIT, 0); + ao_gpio_set_mode(TPB_PORT, TPB_BIT, 0); + ao_gpio_set_mode(TPA_PORT, TPA_BIT, 0); + + MUX_CONTROL = _MUX_1802; + } } -static void -ao_set_arm(void) +void +MUX_stm(void) { - ao_enable_output(MRD_PORT, MRD_BIT, MRD_PIN, 1); - ao_enable_output(MWR_PORT, MWR_BIT, MWR_PIN, 1); - ao_enable_output(TPB_PORT, TPB_BIT, TPB_PIN, 0); - ao_enable_output(TPA_PORT, TPA_BIT, TPA_PIN, 0); - ao_gpio_set(MUX_PORT, MUX_BIT, MUX_PIN, 1); - MUX_CONTROL = MUX_STM; + if (MUX_CONTROL != _MUX_STM) { + /* Set the pins back to pull to the idle value */ + ao_gpio_set_mode(MRD_PORT, MRD_BIT, AO_EXTI_MODE_PULL_UP); + ao_gpio_set_mode(MWR_PORT, MWR_BIT, AO_EXTI_MODE_PULL_UP); + ao_gpio_set_mode(TPB_PORT, TPB_BIT, AO_EXTI_MODE_PULL_DOWN); + ao_gpio_set_mode(TPA_PORT, TPA_BIT, AO_EXTI_MODE_PULL_DOWN); + + ao_gpio_set(MUX_PORT, MUX_BIT, MUX_PIN, 1); + + /* Now set the pins as output, driven to the idle value */ + ao_set_output(MRD_PORT, MRD_BIT, MRD_PIN, 1); + ao_set_output(MWR_PORT, MWR_BIT, MWR_PIN, 1); + ao_set_output(TPB_PORT, TPB_BIT, TPB_PIN, 0); + ao_set_output(TPA_PORT, TPA_BIT, TPA_PIN, 0); + ao_set_output_mask(MA_PORT, MA_MASK << MA_SHIFT); + MUX_CONTROL = _MUX_STM; + } } void -ao_1802_control_init(void) +ao_1802_init(void) { - ao_set_1802(); + /* Multiplexed signals*/ + + /* active low signals */ + ao_enable_input(MRD_PORT, MRD_BIT, AO_EXTI_MODE_PULL_UP); + ao_enable_input(MWR_PORT, MWR_BIT, AO_EXTI_MODE_PULL_UP); + + /* active high signals with interrupts */ + ao_exti_setup(TPA_PORT, TPA_BIT, + AO_EXTI_MODE_PULL_DOWN | AO_EXTI_MODE_RISING | AO_EXTI_MODE_FALLING, + tpa_isr); + ao_exti_setup(TPB_PORT, TPB_BIT, + AO_EXTI_MODE_PULL_DOWN | AO_EXTI_MODE_RISING | AO_EXTI_MODE_FALLING, + tpb_isr); + + /* multiplexed address bus */ + ao_enable_input_mask(MA_PORT, MA_MASK << MA_SHIFT, 0); + + /* Data bus */ + + ao_enable_input_mask(BUS_PORT, BUS_MASK << BUS_SHIFT, 0); + + /* Pins controlled by 1802 */ + ao_enable_input_mask(SC_PORT, SC_MASK << SC_SHIFT, 0); + ao_enable_input(Q_PORT, Q_BIT, 0); + ao_enable_input_mask(N_PORT, N_MASK << N_SHIFT, 0); + + /* Pins controlled by STM */ + ao_enable_output_mask(EF_PORT, 0, EF_MASK << EF_SHIFT); + ao_enable_output(DMA_IN_PORT, DMA_IN_BIT, DMA_IN_PIN, 1); + ao_enable_output(DMA_OUT_PORT, DMA_OUT_BIT, DMA_OUT_PIN, 1); + ao_enable_output(INT_PORT, INT_BIT, INT_PIN, 1); + ao_enable_output(CLEAR_PORT, CLEAR_BIT, CLEAR_PIN, 1); + ao_enable_output(WAIT_PORT, WAIT_BIT, WAIT_PIN, 1); - ao_1802_in(Q_PORT, Q_BIT, q_isr); - (void) MA_set; - (void) DATA_set; - (void) ao_set_arm; + /* Force configuration to STM so that MUX_1802 will do something */ + MUX_CONTROL = _MUX_STM; + MUX_1802(); } diff --git a/src/cortexelf-v1/ao_1802.h b/src/cortexelf-v1/ao_1802.h index daa49f66..5ea89fee 100644 --- a/src/cortexelf-v1/ao_1802.h +++ b/src/cortexelf-v1/ao_1802.h @@ -15,20 +15,115 @@ #ifndef _AO_1802_H_ #define _AO_1802_H_ -/* Signals muxed between 1802 and STM */ -extern uint8_t MRD, TPB, TPA, MWR; - /* Decoded address driven by TPA/TPB signals */ extern uint16_t ADDRESS; /* Decoded data, driven by TPB signal */ extern uint8_t DATA; -extern uint8_t SC; +uint8_t +MRD(void); + +void +MRD_set(uint8_t value); + +uint8_t +MWR(void); + +void +MWR_set(uint8_t value); + +uint8_t +TPA(void); + +void +TPA_set(uint8_t tpa); + +uint8_t +TPB(void); + +void +TPB_set(uint8_t tpb); + +uint8_t +MA(void); + +void +MA_set(uint8_t ma); + +/* Tri-state data bus */ + +uint8_t +BUS(void); + +void +BUS_set(uint8_t bus); + +void +BUS_stm(void); + +void +BUS_1802(void); + +/* Pins controlled by 1802 */ +uint8_t +SC(void); + +uint8_t +Q(void); + +uint8_t +N(void); + +/* Pins controlled by STM */ +uint8_t +EF(void); + +void +EF_set(uint8_t ef); + +uint8_t +DMA_IN(void); + +void +DMA_IN_set(uint8_t dma_in); + +uint8_t +DMA_OUT(void); + +void +DMA_OUT_set(uint8_t dma_out); + +uint8_t +INT(void); + +void +INT_set(uint8_t dma_out); + +uint8_t +CLEAR(void); + +void +CLEAR_set(uint8_t dma_out); + +uint8_t +WAIT(void); + +void +WAIT_set(uint8_t dma_out); #define SC_FETCH 0 #define SC_EXECUTE 1 #define SC_DMA 2 #define SC_INTERRUPT 3 +void +MUX_1802(void); + +void +MUX_stm(void); + +void +ao_1802_init(void); + #endif /* _AO_1802_H_ */ diff --git a/src/cortexelf-v1/ao_cortexelf.c b/src/cortexelf-v1/ao_cortexelf.c index 77fbd0c0..decd6ef5 100644 --- a/src/cortexelf-v1/ao_cortexelf.c +++ b/src/cortexelf-v1/ao_cortexelf.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include struct ao_task ball_task; @@ -274,6 +276,10 @@ main(void) ao_as1107_init(); + ao_1802_init(); + + ao_hex_init(); + ao_config_init(); ao_add_task(&ball_task, ao_ball, "ball"); diff --git a/src/cortexelf-v1/ao_flip_bits.5c b/src/cortexelf-v1/ao_flip_bits.5c index 055d5299..cd5507cc 100644 --- a/src/cortexelf-v1/ao_flip_bits.5c +++ b/src/cortexelf-v1/ao_flip_bits.5c @@ -1,19 +1,24 @@ #!/usr/bin/nickle -int flip_bits(int a) +int flip_bits(int a, int n) { int result = 0; - for (int pos = 0; pos < 8; pos++) + for (int pos = 0; pos < n; pos++) if ((a & (1 << pos)) != 0) - result |= (1 << (7 - pos)); + result |= (1 << (n - 1 - pos)); return result; } -printf ("static const uint8_t ao_flip_bits[256] = {\n"); +void print_flip_bits(string name, int n) { + printf ("static const uint8_t %s_%d[%d] = {\n", name, n, 1 << n); -for (int i = 0; i < 256; i++) { - printf (" 0x%02x,", flip_bits(i)); - if ((i & 0xf) == 0xf) - printf("\n"); + for (int i = 0; i < 1 << n; i++) { + printf (" 0x%02x,", flip_bits(i, n)); + if ((i & 0xf) == 0xf) + printf("\n"); + } + printf("};\n"); } -printf("};\n"); + +print_flip_bits("ao_flip_bits", 8); +print_flip_bits("ao_flip_bits", 2); diff --git a/src/cortexelf-v1/ao_hex.c b/src/cortexelf-v1/ao_hex.c new file mode 100644 index 00000000..1507407b --- /dev/null +++ b/src/cortexelf-v1/ao_hex.c @@ -0,0 +1,36 @@ +/* + * Copyright © 2017 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include "ao_hex.h" +#include "ao_as1107.h" +#include "ao_1802.h" + +static struct ao_task ao_hex_task; + +static void +ao_hex(void) +{ + for (;;) { + ao_as1107_write_16(0, ADDRESS); + ao_as1107_write_8(6, DATA); + ao_sleep(&ADDRESS); + } +} + +void +ao_hex_init(void) +{ + ao_add_task(&ao_hex_task, ao_hex, "hex"); +} diff --git a/src/cortexelf-v1/ao_hex.h b/src/cortexelf-v1/ao_hex.h new file mode 100644 index 00000000..674c1eee --- /dev/null +++ b/src/cortexelf-v1/ao_hex.h @@ -0,0 +1,21 @@ +/* + * Copyright © 2017 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _AO_HEX_H_ +#define _AO_HEX_H_ + +void +ao_hex_init(void); + +#endif /* _AO_HEX_H_ */ diff --git a/src/cortexelf-v1/ao_pins.h b/src/cortexelf-v1/ao_pins.h index d580ce3d..50add5d3 100644 --- a/src/cortexelf-v1/ao_pins.h +++ b/src/cortexelf-v1/ao_pins.h @@ -207,12 +207,6 @@ #define AO_MATRIX_COL_3_PIN 6 /* 1802 connections */ -#define MA_PORT (&stm_gpioe) -#define MA_SHIFT 0 - -#define DATA_PORT (&stm_gpioe) -#define DATA_SHIFT 8 - #define MRD_PORT (&stm_gpiob) #define MRD_BIT 15 @@ -225,34 +219,45 @@ #define TPA_PORT (&stm_gpioa) #define TPA_BIT 6 -#define MUX_PORT (&stm_gpiob) -#define MUX_BIT 1 +#define MA_PORT (&stm_gpioe) +#define MA_SHIFT 0 +#define MA_MASK 0xff -#define WAIT_PORT (&stm_gpioa) -#define WAIT_PIN 4 +#define BUS_PORT (&stm_gpioe) +#define BUS_SHIFT 8 +#define BUS_MASK 0xff -#define CLEAR_PORT (&stm_gpioa) -#define CLEAR_PIN 10 +#define SC_PORT (&stm_gpiob) +#define SC_SHIFT 13 +#define SC_MASK 3 #define Q_PORT (&stm_gpiob) #define Q_BIT 12 -#define SC_PORT (&stm_gpiob) -#define SC_SHIFT 13 - #define N_PORT (&stm_gpiod) #define N_SHIFT 13 +#define N_MASK 7 + +#define EF_PORT (&stm_gpiob) +#define EF_SHIFT 8 +#define EF_MASK 0xf #define DMA_IN_PORT (&stm_gpioa) -#define DMA_IN_PIN 0 +#define DMA_IN_BIT 0 #define DMA_OUT_PORT (&stm_gpioa) -#define DMA_OUT_PIN 9 +#define DMA_OUT_BIT 9 -#define INTERRUPT_PORT (&stm_gpioa) -#define INTERRUPT_PIN 2 +#define INT_PORT (&stm_gpioa) +#define INT_BIT 2 -#define EF_PORT (&stm_gpiob) -#define EF_SHIFT 8 +#define CLEAR_PORT (&stm_gpioa) +#define CLEAR_BIT 10 + +#define WAIT_PORT (&stm_gpioa) +#define WAIT_BIT 4 + +#define MUX_PORT (&stm_gpiob) +#define MUX_BIT 1 #endif /* _AO_PINS_H_ */ -- cgit v1.2.3 From a68fb412589819980759d49565a084b23eee8b8f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 9 Apr 2017 12:51:49 -0700 Subject: altos: Place AS1107 in 'normal' mode at end of init sequence This makes sure the device is out of reset mode while initializing, and then placed in normal mode to turn on the display. Signed-off-by: Keith Packard --- src/drivers/ao_as1107.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/drivers/ao_as1107.c b/src/drivers/ao_as1107.c index 0b83ab2c..e0172d95 100644 --- a/src/drivers/ao_as1107.c +++ b/src/drivers/ao_as1107.c @@ -44,8 +44,10 @@ _ao_as1107_setup(void) if (!as1107_configured) { as1107_configured = 1; _ao_as1107_cmd(AO_AS1107_SHUTDOWN, AO_AS1107_SHUTDOWN_SHUTDOWN_RESET); + _ao_as1107_cmd(AO_AS1107_SHUTDOWN, AO_AS1107_SHUTDOWN_SHUTDOWN_NOP); _ao_as1107_cmd(AO_AS1107_DECODE_MODE, AO_AS1107_DECODE); _ao_as1107_cmd(AO_AS1107_SCAN_LIMIT, AO_AS1107_NUM_DIGITS - 1); + _ao_as1107_cmd(AO_AS1107_INTENSITY, 0x0f); _ao_as1107_cmd(AO_AS1107_FEATURE, (0 << AO_AS1107_FEATURE_CLK_EN) | (0 << AO_AS1107_FEATURE_REG_RES) | @@ -55,6 +57,7 @@ _ao_as1107_setup(void) (0 << AO_AS1107_FEATURE_BLINK_FREQ) | (0 << AO_AS1107_FEATURE_SYNC) | (0 << AO_AS1107_FEATURE_BLINK_START)); + _ao_as1107_cmd(AO_AS1107_SHUTDOWN, AO_AS1107_SHUTDOWN_NORMAL_NOP); } } -- cgit v1.2.3 From 24cd5dd33ccf65c1b277911c460a89ec2b52e421 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 9 Apr 2017 12:53:34 -0700 Subject: altos: Drive row low instead of high in matrix driver Driving it high won't work all that well as we're looking for zero bits. Signed-off-by: Keith Packard --- src/drivers/ao_matrix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_matrix.c b/src/drivers/ao_matrix.c index e0f8ba75..fa2d0c57 100644 --- a/src/drivers/ao_matrix.c +++ b/src/drivers/ao_matrix.c @@ -89,9 +89,9 @@ _ao_matrix_read_cols(void) static uint8_t _ao_matrix_read(uint8_t row) { uint8_t state; - _ao_matrix_drive_row(row, 1); - state = _ao_matrix_read_cols(); _ao_matrix_drive_row(row, 0); + state = _ao_matrix_read_cols(); + _ao_matrix_drive_row(row, 1); return state; } -- cgit v1.2.3 From 83c1e4e8ca684f555cba252efd3882f811d8e154 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 9 Apr 2017 12:54:57 -0700 Subject: altos: Document a few more SPI mode bits in VGA driver Just comment changes Signed-off-by: Keith Packard --- src/drivers/ao_vga.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_vga.c b/src/drivers/ao_vga.c index 2d05d522..909e3109 100644 --- a/src/drivers/ao_vga.c +++ b/src/drivers/ao_vga.c @@ -139,13 +139,13 @@ ao_vga_init(void) (0 << STM_SPI_CR1_CRCEN) | /* CRC disabled */ (0 << STM_SPI_CR1_CRCNEXT) | (1 << STM_SPI_CR1_DFF) | - (0 << STM_SPI_CR1_RXONLY) | + (0 << STM_SPI_CR1_RXONLY) | /* transmit, not receive */ (0 << STM_SPI_CR1_SSM) | /* Software SS handling */ (1 << STM_SPI_CR1_SSI) | /* ... */ (1 << STM_SPI_CR1_LSBFIRST) | /* Little endian */ (1 << STM_SPI_CR1_SPE) | /* Enable SPI unit */ (0 << STM_SPI_CR1_BR) | /* baud rate to pclk/2 */ - (0 << STM_SPI_CR1_MSTR) | + (0 << STM_SPI_CR1_MSTR) | /* slave */ (0 << STM_SPI_CR1_CPOL) | /* Format 0 */ (0 << STM_SPI_CR1_CPHA)); stm_spi1.cr2 = ((0 << STM_SPI_CR2_TXEIE) | -- cgit v1.2.3 From 9e80b8bd10433ecc6ebe7c295e16b62b3883987d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 9 Apr 2017 12:55:34 -0700 Subject: altos: Escape lisp REP loop with () input Provide a way to get out of a lisp read-eval-print loop that can be easily input from the keyboard. Signed-off-by: Keith Packard --- src/lisp/ao_lisp_rep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lisp/ao_lisp_rep.c b/src/lisp/ao_lisp_rep.c index ef7dbaf2..3be95d44 100644 --- a/src/lisp/ao_lisp_rep.c +++ b/src/lisp/ao_lisp_rep.c @@ -20,7 +20,7 @@ ao_lisp_read_eval_print(void) ao_poly in, out = AO_LISP_NIL; for(;;) { in = ao_lisp_read(); - if (in == _ao_lisp_atom_eof) + if (in == _ao_lisp_atom_eof || in == AO_LISP_NIL) break; out = ao_lisp_eval(in); if (ao_lisp_exception) { -- cgit v1.2.3 From c97b4c65d66078a4e187b782669e6b36ee92d30c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 9 Apr 2017 12:56:59 -0700 Subject: altos: Use MP switch in cortexelf boot loader for force loader mode Provide a way to get to the boot loader on the cortexelf board by turning the MP switch on. Signed-off-by: Keith Packard --- src/cortexelf-v1/flash-loader/ao_pins.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/cortexelf-v1/flash-loader/ao_pins.h b/src/cortexelf-v1/flash-loader/ao_pins.h index a34bcb6c..5d63dc2c 100644 --- a/src/cortexelf-v1/flash-loader/ao_pins.h +++ b/src/cortexelf-v1/flash-loader/ao_pins.h @@ -24,12 +24,12 @@ #include -/* Companion port cs_companion0 PB6 */ +/* MP switch, gpioc 9 */ #define AO_BOOT_PIN 1 -#define AO_BOOT_APPLICATION_GPIO stm_gpiob -#define AO_BOOT_APPLICATION_PIN 0 +#define AO_BOOT_APPLICATION_GPIO stm_gpioc +#define AO_BOOT_APPLICATION_PIN 9 #define AO_BOOT_APPLICATION_VALUE 1 -#define AO_BOOT_APPLICATION_MODE AO_EXTI_MODE_PULL_UP +#define AO_BOOT_APPLICATION_MODE 0 #endif /* _AO_PINS_H_ */ -- cgit v1.2.3 From 6efa53bafda18313742849a6c4992f09c3e403c3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 9 Apr 2017 12:59:07 -0700 Subject: cortexelf-v1: Bump SPI pin speed to 40MHz to for sdcard. Fix VGA DMA. Tell the DMA code to leave the DMA engine enabled so the VGA output can use it. Signed-off-by: Keith Packard --- src/cortexelf-v1/ao_pins.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/cortexelf-v1/ao_pins.h b/src/cortexelf-v1/ao_pins.h index 50add5d3..258ffe31 100644 --- a/src/cortexelf-v1/ao_pins.h +++ b/src/cortexelf-v1/ao_pins.h @@ -90,12 +90,12 @@ #define HAS_SPI_2 1 #define SPI_2_PB13_PB14_PB15 0 #define SPI_2_PD1_PD3_PD4 1 /* LED displays, microSD */ -#define SPI_2_OSPEEDR STM_OSPEEDR_10MHz +#define SPI_2_OSPEEDR STM_OSPEEDR_40MHz #define SPI_2_PORT (&stm_gpiod) -#define SPI_2_SCK_PIN 1 -#define SPI_2_MISO_PIN 3 -#define SPI_2_MOSI_PIN 4 +//#define SPI_2_SCK_PIN 1 +//#define SPI_2_MISO_PIN 3 +//#define SPI_2_MOSI_PIN 4 #define HAS_I2C_1 0 #define I2C_1_PB8_PB9 0 @@ -125,6 +125,8 @@ #define AO_SDCARD_SPI_MISO_PIN 3 #define AO_SDCARD_SPI_MOSI_PIN 4 +/* VGA */ +#define STM_DMA1_3_STOLEN 1 /* Buttons */ #define AO_EVENT 1 -- cgit v1.2.3 From eb0b2b4e9f56d1d6fc2b06e39c8372dfcdf3b1f5 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 9 Apr 2017 13:03:50 -0700 Subject: cortexelf-v1: Initialize key matrix code This gets the hex keypad working. Signed-off-by: Keith Packard --- src/cortexelf-v1/ao_cortexelf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cortexelf-v1/ao_cortexelf.c b/src/cortexelf-v1/ao_cortexelf.c index decd6ef5..61a9d219 100644 --- a/src/cortexelf-v1/ao_cortexelf.c +++ b/src/cortexelf-v1/ao_cortexelf.c @@ -275,7 +275,7 @@ main(void) ao_button_init(); ao_as1107_init(); - + ao_matrix_init(); ao_1802_init(); ao_hex_init(); -- cgit v1.2.3 From f18793efb1fbfd17963b9146fae084f2b843d7a3 Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Thu, 13 Apr 2017 19:36:49 -0600 Subject: initial cut at telegps-v2.0 firmware --- src/telegps-v2.0/Makefile | 92 ++++++++++++++++++ src/telegps-v2.0/ao_pins.h | 162 ++++++++++++++++++++++++++++++++ src/telegps-v2.0/ao_telegps.c | 68 ++++++++++++++ src/telegps-v2.0/flash-loader/Makefile | 8 ++ src/telegps-v2.0/flash-loader/ao_pins.h | 36 +++++++ 5 files changed, 366 insertions(+) create mode 100644 src/telegps-v2.0/Makefile create mode 100644 src/telegps-v2.0/ao_pins.h create mode 100644 src/telegps-v2.0/ao_telegps.c create mode 100644 src/telegps-v2.0/flash-loader/Makefile create mode 100644 src/telegps-v2.0/flash-loader/ao_pins.h (limited to 'src') diff --git a/src/telegps-v2.0/Makefile b/src/telegps-v2.0/Makefile new file mode 100644 index 00000000..58cf26e8 --- /dev/null +++ b/src/telegps-v2.0/Makefile @@ -0,0 +1,92 @@ +# +# AltOS build +# +# + +include ../stmf0/Makefile.defs + +INC = \ + ao.h \ + ao_arch.h \ + ao_arch_funcs.h \ + ao_pins.h \ + ao_product.h \ + ao_tracker.h \ + ao_task.h \ + ao_whiten.h \ + ao_cc115l.h \ + ao_fec.h \ + stm32f0.h \ + Makefile + + +ALTOS_SRC = \ + ao_adc_stm.c \ + ao_led.c \ + ao_interrupt.c \ + ao_product.c \ + ao_romconfig.c \ + ao_cmd.c \ + ao_config.c \ + ao_task.c \ + ao_stdio.c \ + ao_panic.c \ + ao_timer.c \ + ao_mutex.c \ + ao_freq.c \ + ao_dma_stm.c \ + ao_spi_stm.c \ + ao_usb_stm.c \ + ao_exti_stm.c \ + ao_serial_stm.c \ + ao_gps_ublox.c \ + ao_gps_show.c \ + ao_cc1200.c \ + ao_fec_tx.c \ + ao_aprs.c \ + ao_tracker.c \ + ao_telemetry.c \ + ao_storage.c \ + ao_m25.c \ + ao_log.c \ + ao_log_gps.c \ + ao_distance.c \ + ao_sqrt.c \ + ao_data.c \ + ao_convert_volt.c \ + $(SAMPLE_PROFILE) + +PRODUCT=TeleGPS-v2.0 +PRODUCT_DEF=-DTELEGPS +IDPRODUCT=0x0025 + +CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) $(PROFILE_DEF) -g -Os + +PROGNAME=telegps-v2.0 +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +SRC=$(ALTOS_SRC) ao_telegps.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +LDFLAGS=-L../stmf0 -Wl,-Taltos.ld + +$(PROG): Makefile $(OBJ) altos.ld + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +$(OBJ): $(INC) + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean: clean + +clean: + rm -f *.o ao_serial_stm.h $(PROGNAME)-*.elf $(PROGNAME)-*.ihx + rm -f ao_product.h + +install: + +uninstall: diff --git a/src/telegps-v2.0/ao_pins.h b/src/telegps-v2.0/ao_pins.h new file mode 100644 index 00000000..acba8c37 --- /dev/null +++ b/src/telegps-v2.0/ao_pins.h @@ -0,0 +1,162 @@ +/* + * Copyright © 2017 Bdale Garbee + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define LED_PORT_ENABLE STM_RCC_AHBENR_IOPBEN +#define LED_PORT (&stm_gpiob) +#define LED_PIN_RED 5 +#define AO_LED_RED (1 << LED_PIN_RED) + +#define LEDS_AVAILABLE (AO_LED_RED) + +#define HAS_BEEP 0 + +#define AO_HSE 32000000 +#define AO_RCC_CFGR_PLLMUL STM_RCC_CFGR_PLLMUL_3 +#define AO_PLLMUL 3 +#define AO_PLLDIV 1 + +/* HCLK = 48MHz */ +#define AO_AHB_PRESCALER 1 +#define AO_RCC_CFGR_HPRE_DIV STM_RCC_CFGR_HPRE_DIV_1 + +/* APB = 48MHz */ +#define AO_APB_PRESCALER 1 +#define AO_RCC_CFGR_PPRE_DIV STM_RCC_CFGR_PPRE_DIV_1 + +#define AO_RCC_CFGR2_PLLDIV STM_RCC_CFGR2_PREDIV_1 + +#define HAS_USB 1 +#define AO_USB_DIRECTIO 0 +#define AO_PA11_PA12_RMP 1 + +#define IS_FLASH_LOADER 0 + +/* ADC */ + +#define HAS_ADC 1 +#define AO_ADC_PIN0_PORT (&stm_gpioa) +#define AO_ADC_PIN0_PIN 0 +#define AO_ADC_PIN0_CH 0 + +#define AO_ADC_RCC_AHBENR ((1 << STM_RCC_AHBENR_IOPAEN)) + +#define AO_NUM_ADC 1 + +#define AO_DATA_RING 4 + +/* + * Voltage divider on ADC battery sampler + */ +#define AO_BATTERY_DIV_PLUS 56 /* 5.6k */ +#define AO_BATTERY_DIV_MINUS 100 /* 10k */ + +/* + * ADC reference in decivolts + */ +#define AO_ADC_REFERENCE_DV 33 + +struct ao_adc { + int16_t v_batt; +}; + +#define AO_ADC_DUMP(p) \ + printf("tick: %5u batt: %5d\n", \ + (p)->tick, \ + (p)->adc.v_batt) + +/* SPI */ +#define HAS_SPI_1 1 +#define HAS_SPI_2 0 +#define SPI_1_PA5_PA6_PA7 1 +#define SPI_1_PB3_PB4_PB5 0 +#define SPI_1_OSPEEDR STM_OSPEEDR_HIGH + +#define HAS_MS5607 0 + +/* Flash */ + +#define M25_MAX_CHIPS 1 +#define AO_M25_SPI_CS_PORT (&stm_gpiob) +#define AO_M25_SPI_CS_MASK (1 << 0) +#define AO_M25_SPI_BUS AO_SPI_1_PA5_PA6_PA7 + +#define HAS_SERIAL_1 1 +#define SERIAL_1_PB6_PB7 1 +#define USE_SERIAL_1_STDIN 0 + +#define ao_gps_getchar ao_serial1_getchar +#define ao_gps_putchar ao_serial1_putchar +#define ao_gps_set_speed ao_serial1_set_speed +#define ao_gps_fifo (ao_usart_rx_fifo) + +#define HAS_EEPROM 1 +#define USE_INTERNAL_FLASH 0 +#define HAS_RADIO 1 +#define HAS_TELEMETRY 1 +#define HAS_RDF 1 +#define HAS_APRS 1 +#define HAS_RADIO_RECV 0 + +#define HAS_GPS 1 +#define HAS_FLIGHT 0 +#define HAS_LOG 1 +#define FLIGHT_LOG_APPEND 1 +#define HAS_TRACKER 1 + +#define AO_CONFIG_DEFAULT_APRS_INTERVAL 0 +#define AO_CONFIG_DEFAULT_RADIO_POWER 0xc0 + +/* + * GPS + */ + +#define AO_SERIAL_SPEED_UBLOX AO_SERIAL_SPEED_9600 + + +/* + * Radio (cc1120) + */ + +/* gets pretty close to 434.550 */ + +#define AO_RADIO_CAL_DEFAULT 5695733 + +#define AO_FEC_DEBUG 0 +#define AO_CC1200_SPI_CS_PORT (&stm_gpioa) +#define AO_CC1200_SPI_CS_PIN 5 +#define AO_CC1200_SPI_BUS AO_SPI_1_PA5_PA6_PA7 +#define AO_CC1200_SPI stm_spi1 +#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST + +#define AO_CC1200_INT_PORT (&stm_gpioa) +#define AO_CC1200_INT_PIN 4 +#define AO_CC1200_MCU_WAKEUP_PORT (&stm_gpioa) +#define AO_CC1200_MCU_WAKEUP_PIN (0) + +#define AO_CC1200_INT_GPIO 2 +#define AO_CC1200_INT_GPIO_IOCFG CC1200_IOCFG2 + +#define AO_CC1200_MARC_GPIO 3 +#define AO_CC1200_MARC_GPIO_IOCFG CC1200_IOCFG3 + +#define HAS_BOOT_RADIO 0 + +#endif /* _AO_PINS_H_ */ diff --git a/src/telegps-v2.0/ao_telegps.c b/src/telegps-v2.0/ao_telegps.c new file mode 100644 index 00000000..7a923d11 --- /dev/null +++ b/src/telegps-v2.0/ao_telegps.c @@ -0,0 +1,68 @@ +/* + * Copyright © 2013 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include +#include + +int +main(void) +{ + ao_clock_init(); + +#if HAS_STACK_GUARD + ao_mpu_init(); +#endif + + ao_task_init(); + ao_timer_init(); + + ao_spi_init(); + ao_exti_init(); + + ao_storage_init(); + + ao_serial_init(); + + ao_cmd_init(); + + ao_usb_init(); + ao_radio_init(); + +#if HAS_ADC + ao_adc_init(); +#endif + + ao_gps_init(); +#if HAS_LOG + ao_log_init(); +#endif + + ao_tracker_init(); + + ao_telemetry_init(); + +#if HAS_SAMPLE_PROFILE + ao_sample_profile_init(); +#endif + ao_config_init(); + + ao_start_scheduler(); + return 0; +} diff --git a/src/telegps-v2.0/flash-loader/Makefile b/src/telegps-v2.0/flash-loader/Makefile new file mode 100644 index 00000000..c0659698 --- /dev/null +++ b/src/telegps-v2.0/flash-loader/Makefile @@ -0,0 +1,8 @@ +# +# AltOS flash loader build +# +# + +TOPDIR=../.. +HARDWARE=telegps-v2.0 +include $(TOPDIR)/stmf0/Makefile-flash.defs diff --git a/src/telegps-v2.0/flash-loader/ao_pins.h b/src/telegps-v2.0/flash-loader/ao_pins.h new file mode 100644 index 00000000..a83dbaa2 --- /dev/null +++ b/src/telegps-v2.0/flash-loader/ao_pins.h @@ -0,0 +1,36 @@ +/* + * Copyright © 2017 Bdale Garbee + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#include + +/* Pin 5 on debug connector */ + +#define AO_BOOT_PIN 1 +#define AO_BOOT_APPLICATION_GPIO stm_gpioa +#define AO_BOOT_APPLICATION_PIN 15 +#define AO_BOOT_APPLICATION_VALUE 1 +#define AO_BOOT_APPLICATION_MODE AO_EXTI_MODE_PULL_UP + +#define HAS_USB 1 +#define AO_USB_DIRECTIO 0 +#define AO_PA11_PA12_RMP 1 + +#endif /* _AO_PINS_H_ */ -- cgit v1.2.3 From 3390c62b6d0761764ec5249d72bda33b984a8f90 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 13 Apr 2017 21:16:52 -0600 Subject: altos/telegps: Inherit LDFLAGS from lpc make specification Somethings messed up with cortex-M0 linking, and this isn't helping as it overrides the LDFLAGS coming from the architecture. Signed-off-by: Keith Packard --- src/telegps-v0.3/Makefile | 2 -- src/telegps-v1.0/Makefile | 2 -- 2 files changed, 4 deletions(-) (limited to 'src') diff --git a/src/telegps-v0.3/Makefile b/src/telegps-v0.3/Makefile index 1eaf7c47..834609d9 100644 --- a/src/telegps-v0.3/Makefile +++ b/src/telegps-v0.3/Makefile @@ -67,8 +67,6 @@ OBJ=$(SRC:.c=.o) all: $(PROG) $(HEX) -LDFLAGS=-L../lpc -Wl,-Taltos.ld - $(PROG): Makefile $(OBJ) altos.ld $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) diff --git a/src/telegps-v1.0/Makefile b/src/telegps-v1.0/Makefile index bd13cfe7..76dc0371 100644 --- a/src/telegps-v1.0/Makefile +++ b/src/telegps-v1.0/Makefile @@ -70,8 +70,6 @@ OBJ=$(SRC:.c=.o) all: $(PROG) $(HEX) -LDFLAGS=-L../lpc -Wl,-Taltos.ld - $(PROG): Makefile $(OBJ) altos.ld $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) -- cgit v1.2.3 From a5c8b8c59f99108233d99ceceb6f85315694e4b1 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 13 Apr 2017 21:18:58 -0600 Subject: cortexelf-v1: Fetch data at TPB rising when MWR or MRD are low This should get the right value at least. Signed-off-by: Keith Packard --- src/cortexelf-v1/ao_1802.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/cortexelf-v1/ao_1802.c b/src/cortexelf-v1/ao_1802.c index b7e11637..9fb36595 100644 --- a/src/cortexelf-v1/ao_1802.c +++ b/src/cortexelf-v1/ao_1802.c @@ -73,14 +73,14 @@ static void TPB_rising(void) { ADDRESS = (ADDRESS & 0xff00) | MA(); + if (MWR() == 0 || MRD() == 0) + DATA = BUS(); ao_wakeup(&ADDRESS); } static void TPB_falling(void) { - DATA = BUS(); - ao_wakeup(&ADDRESS); } uint8_t -- cgit v1.2.3 From 4e561ae43a734d870470e36c41232482bd5f398f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 13 Apr 2017 21:47:14 -0600 Subject: altos/stmf0: Split up rom load in altos.ld to make linker happy The linker isn't happy when the .ld file tries to add text, the .exidx and .rodata segments in the same block. Split them up for success. Signed-off-by: Keith Packard --- src/stmf0/altos.ld | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/stmf0/altos.ld b/src/stmf0/altos.ld index 8f8933c6..74fdf3ea 100644 --- a/src/stmf0/altos.ld +++ b/src/stmf0/altos.ld @@ -55,10 +55,16 @@ SECTIONS { ao_product.o(.romconfig*) *(.text*) /* Executable code */ + } > rom + + .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) - *(.rodata*) /* Constants */ + } > rom + .rodata : { + *(.rodata*) /* Constants */ } > rom + __text_end__ = .; /* Boot data which must live at the start of ram so that -- cgit v1.2.3 From f69d85e2b32370ab68e2725e739417cad6d7a590 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 13 Apr 2017 21:48:46 -0600 Subject: telegps-v2.0: Remove fec_tx code and ADC logging. This gets telegps-v2.0 to link. Signed-off-by: Keith Packard --- src/telegps-v2.0/Makefile | 9 +++------ src/telegps-v2.0/ao_pins.h | 2 ++ 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/telegps-v2.0/Makefile b/src/telegps-v2.0/Makefile index 58cf26e8..19d088d3 100644 --- a/src/telegps-v2.0/Makefile +++ b/src/telegps-v2.0/Makefile @@ -13,8 +13,7 @@ INC = \ ao_product.h \ ao_tracker.h \ ao_task.h \ - ao_whiten.h \ - ao_cc115l.h \ + ao_cc1200.h \ ao_fec.h \ stm32f0.h \ Makefile @@ -24,6 +23,7 @@ ALTOS_SRC = \ ao_adc_stm.c \ ao_led.c \ ao_interrupt.c \ + ao_boot_chain.c \ ao_product.c \ ao_romconfig.c \ ao_cmd.c \ @@ -42,7 +42,6 @@ ALTOS_SRC = \ ao_gps_ublox.c \ ao_gps_show.c \ ao_cc1200.c \ - ao_fec_tx.c \ ao_aprs.c \ ao_tracker.c \ ao_telemetry.c \ @@ -71,10 +70,8 @@ OBJ=$(SRC:.c=.o) all: $(PROG) $(HEX) -LDFLAGS=-L../stmf0 -Wl,-Taltos.ld - $(PROG): Makefile $(OBJ) altos.ld - $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS) $(OBJ): $(INC) diff --git a/src/telegps-v2.0/ao_pins.h b/src/telegps-v2.0/ao_pins.h index acba8c37..c51f0afb 100644 --- a/src/telegps-v2.0/ao_pins.h +++ b/src/telegps-v2.0/ao_pins.h @@ -26,6 +26,7 @@ #define LEDS_AVAILABLE (AO_LED_RED) +#define IS_FLASH_LOADER 0 #define HAS_BEEP 0 #define AO_HSE 32000000 @@ -120,6 +121,7 @@ struct ao_adc { #define HAS_LOG 1 #define FLIGHT_LOG_APPEND 1 #define HAS_TRACKER 1 +#define LOG_ADC 0 #define AO_CONFIG_DEFAULT_APRS_INTERVAL 0 #define AO_CONFIG_DEFAULT_RADIO_POWER 0xc0 -- cgit v1.2.3 From 207403e53cc80b0649ce3c004f97d8e1dad824c8 Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Tue, 18 Apr 2017 16:33:27 -0600 Subject: copy telefiretwo-v0.2 to start firmware for v1.0 --- src/telefiretwo-v1.0/ao_pins.h | 211 +++++++++++++++++++++++++++ src/telefiretwo-v1.0/ao_telefiretwo.c | 55 +++++++ src/telefiretwo-v1.0/flash-loader/.gitignore | 2 + src/telefiretwo-v1.0/flash-loader/Makefile | 8 + src/telefiretwo-v1.0/flash-loader/ao_pins.h | 33 +++++ 5 files changed, 309 insertions(+) create mode 100644 src/telefiretwo-v1.0/ao_pins.h create mode 100644 src/telefiretwo-v1.0/ao_telefiretwo.c create mode 100644 src/telefiretwo-v1.0/flash-loader/.gitignore create mode 100644 src/telefiretwo-v1.0/flash-loader/Makefile create mode 100644 src/telefiretwo-v1.0/flash-loader/ao_pins.h (limited to 'src') diff --git a/src/telefiretwo-v1.0/ao_pins.h b/src/telefiretwo-v1.0/ao_pins.h new file mode 100644 index 00000000..70af5dd1 --- /dev/null +++ b/src/telefiretwo-v1.0/ao_pins.h @@ -0,0 +1,211 @@ +/* + * Copyright © 2010 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define HAS_RADIO 1 +#define HAS_RADIO_RATE 1 +#define HAS_TELEMETRY 0 + +#define HAS_FLIGHT 0 +#define HAS_USB 1 +#define HAS_BEEP 1 +#define BEEPER_CHANNEL 4 +#define HAS_GPS 0 +#define HAS_SERIAL_1 0 +#define HAS_ADC 1 +#define HAS_DBG 0 +#define HAS_EEPROM 1 +#define HAS_LOG 0 +#define HAS_PAD 1 +#define USE_INTERNAL_FLASH 1 +#define IGNITE_ON_P0 0 +#define PACKET_HAS_MASTER 0 +#define PACKET_HAS_SLAVE 0 +#define AO_DATA_RING 32 +#define HAS_FIXED_PAD_BOX 1 + +/* 8MHz High speed external crystal */ +#define AO_HSE 8000000 + +/* PLLVCO = 96MHz (so that USB will work) */ +#define AO_PLLMUL 12 +#define AO_RCC_CFGR_PLLMUL (STM_RCC_CFGR_PLLMUL_12) + +#define AO_CC1200_FOSC 40000000 + +/* SYSCLK = 32MHz (no need to go faster than CPU) */ +#define AO_PLLDIV 3 +#define AO_RCC_CFGR_PLLDIV (STM_RCC_CFGR_PLLDIV_3) + +/* HCLK = 32MHz (CPU clock) */ +#define AO_AHB_PRESCALER 1 +#define AO_RCC_CFGR_HPRE_DIV STM_RCC_CFGR_HPRE_DIV_1 + +/* Run APB1 at 16MHz (HCLK/2) */ +#define AO_APB1_PRESCALER 2 +#define AO_RCC_CFGR_PPRE1_DIV STM_RCC_CFGR_PPRE2_DIV_2 + +/* Run APB2 at 16MHz (HCLK/2) */ +#define AO_APB2_PRESCALER 2 +#define AO_RCC_CFGR_PPRE2_DIV STM_RCC_CFGR_PPRE2_DIV_2 + +#define HAS_EEPROM 1 +#define USE_INTERNAL_FLASH 1 +#define USE_EEPROM_CONFIG 1 +#define USE_STORAGE_CONFIG 0 +#define HAS_USB 1 +#define HAS_RADIO 1 +#define HAS_RADIO_RATE 1 +#define HAS_TELEMETRY 0 +#define HAS_AES 1 + +#define HAS_SPI_1 0 +#define SPI_1_PA5_PA6_PA7 0 +#define SPI_1_PB3_PB4_PB5 0 +#define SPI_1_PE13_PE14_PE15 0 + +#define HAS_SPI_2 1 /* CC1200 */ +#define SPI_2_PB13_PB14_PB15 1 +#define SPI_2_PD1_PD3_PD4 0 +#define SPI_2_GPIO (&stm_gpiob) +#define SPI_2_SCK 13 +#define SPI_2_MISO 14 +#define SPI_2_MOSI 15 +#define SPI_2_OSPEEDR STM_OSPEEDR_10MHz + +#define HAS_I2C_1 0 + +#define HAS_I2C_2 0 + +#define PACKET_HAS_SLAVE 0 +#define PACKET_HAS_MASTER 0 + +#define FAST_TIMER_FREQ 10000 /* .1ms for debouncing */ + +/* + * Radio is a cc1200 connected via SPI + */ + +#define AO_RADIO_CAL_DEFAULT 5695733 + +#define AO_FEC_DEBUG 0 +#define AO_CC1200_SPI_CS_PORT (&stm_gpioa) +#define AO_CC1200_SPI_CS_PIN 7 +#define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15 +#define AO_CC1200_SPI stm_spi2 + +#define AO_CC1200_INT_PORT (&stm_gpiob) +#define AO_CC1200_INT_PIN (11) + +#define AO_CC1200_INT_GPIO 2 +#define AO_CC1200_INT_GPIO_IOCFG CC1200_IOCFG2 + +#define LED_PORT_0 (&stm_gpioa) +#define LED_PORT_1 (&stm_gpiob) + +#define LED_PORT_0_ENABLE STM_RCC_AHBENR_GPIOAEN +#define LED_PORT_1_ENABLE STM_RCC_AHBENR_GPIOBEN + +/* Port A, pins 4-6 */ +#define LED_PORT_0_SHIFT 4 +#define LED_PORT_0_MASK 0x7 +#define LED_PIN_GREEN 0 +#define LED_PIN_AMBER 1 +#define LED_PIN_RED 2 +#define AO_LED_RED (1 << LED_PIN_RED) +#define AO_LED_AMBER (1 << LED_PIN_AMBER) +#define AO_LED_GREEN (1 << LED_PIN_GREEN) + +/* Port B, pins 4-5 */ +#define LED_PORT_1_SHIFT 0 +#define LED_PORT_1_MASK (0x3 << 4) +#define LED_PIN_CONT_0 4 +#define LED_PIN_ARMED 5 + +#define AO_LED_ARMED (1 << LED_PIN_ARMED) +#define AO_LED_CONTINUITY(c) (1 << (4 - (c))) +#define AO_LED_CONTINUITY_MASK (0x1 << 4) + +#define LEDS_AVAILABLE (LED_PORT_0_MASK|LED_PORT_1_MASK) + +/* Alarm A */ +#define AO_SIREN +#define AO_SIREN_PORT (&stm_gpiob) +#define AO_SIREN_PIN 8 + +/* Alarm B */ +#define AO_STROBE +#define AO_STROBE_PORT (&stm_gpiob) +#define AO_STROBE_PIN 9 + +#define SPI_CONST 0x00 + +#define AO_PAD_NUM 1 +#define AO_PAD_PORT (&stm_gpioa) + +#define AO_PAD_PIN_0 1 +#define AO_PAD_ADC_0 0 + +#define AO_PAD_ALL_PINS ((1 << AO_PAD_PIN_0)) +#define AO_PAD_ALL_CHANNELS ((1 << 0)) + +/* test these values with real igniters */ +#define AO_PAD_RELAY_CLOSED 3524 +#define AO_PAD_NO_IGNITER 16904 +#define AO_PAD_GOOD_IGNITER 22514 + +#define AO_PAD_ADC_PYRO 2 +#define AO_PAD_ADC_BATT 8 + +#define AO_ADC_FIRST_PIN 0 + +#define AO_NUM_ADC 3 + +#define AO_ADC_SQ1 AO_PAD_ADC_0 +#define AO_ADC_SQ2 AO_PAD_ADC_PYRO +#define AO_ADC_SQ3 AO_PAD_ADC_BATT + +#define AO_PYRO_R_PYRO_SENSE 200 +#define AO_PYRO_R_SENSE_GND 22 + +#define AO_FIRE_R_POWER_FET 0 +#define AO_FIRE_R_FET_SENSE 200 +#define AO_FIRE_R_SENSE_GND 22 + +#define HAS_ADC_TEMP 0 + +struct ao_adc { + int16_t sense[AO_PAD_NUM]; + int16_t pyro; + int16_t batt; +}; + +#define AO_ADC_DUMP(p) \ + printf ("tick: %5u 0: %5d pyro: %5d batt %5d\n", \ + (p)->tick, \ + (p)->adc.sense[0], \ + (p)->adc.pyro, \ + (p)->adc.batt) + +#define AO_ADC_PINS ((1 << AO_PAD_ADC_0) | \ + (1 << AO_PAD_ADC_PYRO) | \ + (1 << AO_PAD_ADC_BATT)) + +#endif /* _AO_PINS_H_ */ diff --git a/src/telefiretwo-v1.0/ao_telefiretwo.c b/src/telefiretwo-v1.0/ao_telefiretwo.c new file mode 100644 index 00000000..bdcf3213 --- /dev/null +++ b/src/telefiretwo-v1.0/ao_telefiretwo.c @@ -0,0 +1,55 @@ +/* + * Copyright © 2012 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include +#include + +void +main(void) +{ + ao_clock_init(); + + ao_led_init(LEDS_AVAILABLE); + + ao_task_init(); + + ao_timer_init(); + ao_spi_init(); + ao_dma_init(); + ao_exti_init(); + + ao_cmd_init(); + + ao_adc_init(); + + ao_eeprom_init(); + + ao_radio_init(); + + ao_usb_init(); + + ao_config_init(); + + ao_pad_init(); + +// ao_radio_cmac_cmd_init(); + + ao_start_scheduler(); +} diff --git a/src/telefiretwo-v1.0/flash-loader/.gitignore b/src/telefiretwo-v1.0/flash-loader/.gitignore new file mode 100644 index 00000000..65fe7eab --- /dev/null +++ b/src/telefiretwo-v1.0/flash-loader/.gitignore @@ -0,0 +1,2 @@ +*.elf +*.ihx diff --git a/src/telefiretwo-v1.0/flash-loader/Makefile b/src/telefiretwo-v1.0/flash-loader/Makefile new file mode 100644 index 00000000..2b029ee0 --- /dev/null +++ b/src/telefiretwo-v1.0/flash-loader/Makefile @@ -0,0 +1,8 @@ +# +# AltOS flash loader build +# +# + +TOPDIR=../.. +HARDWARE=telefiretwo-v0.2 +include $(TOPDIR)/stm/Makefile-flash.defs diff --git a/src/telefiretwo-v1.0/flash-loader/ao_pins.h b/src/telefiretwo-v1.0/flash-loader/ao_pins.h new file mode 100644 index 00000000..ded45a40 --- /dev/null +++ b/src/telefiretwo-v1.0/flash-loader/ao_pins.h @@ -0,0 +1,33 @@ +/* + * Copyright © 2013 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +/* External crystal at 8MHz */ +#define AO_HSE 8000000 + +#include + +#define AO_BOOT_PIN 1 +#define AO_BOOT_APPLICATION_GPIO stm_gpiob +#define AO_BOOT_APPLICATION_PIN 6 +#define AO_BOOT_APPLICATION_VALUE 1 +#define AO_BOOT_APPLICATION_MODE AO_EXTI_MODE_PULL_UP + +#endif /* _AO_PINS_H_ */ -- cgit v1.2.3 From 9fa46346d576081f99860cad96c91bcf63233649 Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Tue, 18 Apr 2017 16:47:05 -0600 Subject: builds, loads, runs, not very useful yet --- src/telefiretwo-v1.0/ao_pins.h | 1 + src/telefiretwo-v1.0/flash-loader/Makefile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/telefiretwo-v1.0/ao_pins.h b/src/telefiretwo-v1.0/ao_pins.h index 70af5dd1..469e9937 100644 --- a/src/telefiretwo-v1.0/ao_pins.h +++ b/src/telefiretwo-v1.0/ao_pins.h @@ -110,6 +110,7 @@ #define AO_CC1200_SPI_CS_PIN 7 #define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15 #define AO_CC1200_SPI stm_spi2 +#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST #define AO_CC1200_INT_PORT (&stm_gpiob) #define AO_CC1200_INT_PIN (11) diff --git a/src/telefiretwo-v1.0/flash-loader/Makefile b/src/telefiretwo-v1.0/flash-loader/Makefile index 2b029ee0..d429dcc4 100644 --- a/src/telefiretwo-v1.0/flash-loader/Makefile +++ b/src/telefiretwo-v1.0/flash-loader/Makefile @@ -4,5 +4,5 @@ # TOPDIR=../.. -HARDWARE=telefiretwo-v0.2 +HARDWARE=telefiretwo-v1.0 include $(TOPDIR)/stm/Makefile-flash.defs -- cgit v1.2.3 From 6e699fa4971668bbe569d2a0e2ed9f891877d140 Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Tue, 18 Apr 2017 16:47:43 -0600 Subject: need top level Makefile too --- src/telefiretwo-v1.0/Makefile | 90 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 src/telefiretwo-v1.0/Makefile (limited to 'src') diff --git a/src/telefiretwo-v1.0/Makefile b/src/telefiretwo-v1.0/Makefile new file mode 100644 index 00000000..0a2f9b58 --- /dev/null +++ b/src/telefiretwo-v1.0/Makefile @@ -0,0 +1,90 @@ +# +# TeleFire build file +# + +include ../stm/Makefile.defs + +INC = \ + ao.h \ + ao_pins.h \ + ao_arch.h \ + ao_arch_funcs.h \ + ao_pad.h \ + ao_product.h \ + ao_radio_spi.h \ + ao_radio_cmac.h \ + ao_cc1200_CC1200.h \ + ao_cc1200.h \ + stm32l.h +# +# Common AltOS sources +# + +#PROFILE=ao_profile.c +#PROFILE_DEF=-DAO_PROFILE=1 + +ALTOS_SRC = \ + ao_boot_chain.c \ + ao_interrupt.c \ + ao_product.c \ + ao_romconfig.c \ + ao_cmd.c \ + ao_adc_stm.c \ + ao_data.c \ + ao_config.c \ + ao_task.c \ + ao_led.c \ + ao_stdio.c \ + ao_panic.c \ + ao_timer.c \ + ao_mutex.c \ + ao_freq.c \ + ao_dma_stm.c \ + ao_spi_stm.c \ + ao_beep_stm.c \ + ao_eeprom_stm.c \ + ao_usb_stm.c \ + ao_exti_stm.c \ + ao_cc1200.c \ + ao_radio_cmac.c \ + ao_aes.c \ + ao_aes_tables.c \ + ao_pad.c \ + ao_radio_cmac_cmd.c + +PRODUCT_SRC = \ + ao_telefiretwo.c + +PRODUCT=TeleFire-v1.0 +PRODUCT_DEF=-DTELEFIRETWO_V_1_0 +IDPRODUCT=0x000f + +CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) -Os -g + +PROGNAME = telefiretwo-v1.0 +PROG = $(PROGNAME)-$(VERSION).elf +HEX = $(PROGNAME)-$(VERSION).ihx + +SRC = $(ALTOS_SRC) $(PRODUCT_SRC) +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) altos.ld + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +$(OBJ): $(INC) + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean: clean + +clean: + rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx + rm -f ao_product.h + +install: + +uninstall: + -- cgit v1.2.3 From 1e7143e5d448cd05c355f4a323ae4892b02022ac Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Wed, 19 Apr 2017 15:08:15 -0600 Subject: add new ADC channels for telefiretwo --- src/telefiretwo-v1.0/ao_pins.h | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/telefiretwo-v1.0/ao_pins.h b/src/telefiretwo-v1.0/ao_pins.h index 469e9937..8cde0043 100644 --- a/src/telefiretwo-v1.0/ao_pins.h +++ b/src/telefiretwo-v1.0/ao_pins.h @@ -175,13 +175,18 @@ #define AO_PAD_ADC_PYRO 2 #define AO_PAD_ADC_BATT 8 +#define AO_PAD_ADC_THRUST 3 +#define AO_PAD_ADC_PRESSURE 18 + #define AO_ADC_FIRST_PIN 0 -#define AO_NUM_ADC 3 +#define AO_NUM_ADC 5 #define AO_ADC_SQ1 AO_PAD_ADC_0 #define AO_ADC_SQ2 AO_PAD_ADC_PYRO #define AO_ADC_SQ3 AO_PAD_ADC_BATT +#define AO_ADC_SQ4 AO_PAD_ADC_THRUST +#define AO_ADC_SQ5 AO_PAD_ADC_PRESSURE #define AO_PYRO_R_PYRO_SENSE 200 #define AO_PYRO_R_SENSE_GND 22 @@ -196,17 +201,23 @@ struct ao_adc { int16_t sense[AO_PAD_NUM]; int16_t pyro; int16_t batt; + int16_t thrust; + int16_t pressure; }; #define AO_ADC_DUMP(p) \ - printf ("tick: %5u 0: %5d pyro: %5d batt %5d\n", \ + printf ("tick: %5u 0: %5d pyro: %5d batt %5d thrust %5d pressure %5d\n", \ (p)->tick, \ (p)->adc.sense[0], \ (p)->adc.pyro, \ - (p)->adc.batt) + (p)->adc.batt, \ + (p)->adc.thrust, \ + (p)->adc.pressure) #define AO_ADC_PINS ((1 << AO_PAD_ADC_0) | \ (1 << AO_PAD_ADC_PYRO) | \ - (1 << AO_PAD_ADC_BATT)) + (1 << AO_PAD_ADC_BATT) | \ + (1 << AO_PAD_ADC_THRUST) | \ + (1 << AO_PAD_ADC_PRESSURE)) #endif /* _AO_PINS_H_ */ -- cgit v1.2.3 From 944d8466a31842c34304b77364d632e259238018 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 19 Apr 2017 14:19:28 -0700 Subject: altos/telefiretwo-v0.2: Add AO_CC1200_SPI_SPEED Needed for products with different SPI speed options. Signed-off-by: Keith Packard --- src/telefiretwo-v0.2/ao_pins.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/telefiretwo-v0.2/ao_pins.h b/src/telefiretwo-v0.2/ao_pins.h index 70af5dd1..469e9937 100644 --- a/src/telefiretwo-v0.2/ao_pins.h +++ b/src/telefiretwo-v0.2/ao_pins.h @@ -110,6 +110,7 @@ #define AO_CC1200_SPI_CS_PIN 7 #define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15 #define AO_CC1200_SPI stm_spi2 +#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST #define AO_CC1200_INT_PORT (&stm_gpiob) #define AO_CC1200_INT_PIN (11) -- cgit v1.2.3 From 93983730a6628a2a85b6fc543df236b35d501ee9 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 19 Apr 2017 16:00:24 -0700 Subject: altos/telebt-v3.0: Add LCO bits for testing Add the USB commands for LCO testing to TeleBT v3.0 Signed-off-by: Keith Packard --- src/telebt-v3.0/Makefile | 7 ++++++- src/telebt-v3.0/ao_pins.h | 1 + src/telebt-v3.0/ao_telebt.c | 3 +++ 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/telebt-v3.0/Makefile b/src/telebt-v3.0/Makefile index a7ef4d64..40d1f6e4 100644 --- a/src/telebt-v3.0/Makefile +++ b/src/telebt-v3.0/Makefile @@ -58,7 +58,12 @@ ALTOS_SRC = \ ao_monitor.c \ $(PROFILE) \ $(SAMPLE_PROFILE) \ - $(STACK_GUARD) + $(STACK_GUARD) \ + ao_lco_func.c \ + ao_radio_cmac.c \ + ao_aes.c \ + ao_aes_tables.c \ + ao_lco_cmd.c PRODUCT=TeleBT-v3.0 PRODUCT_DEF=-DTELEBT_V_3_0 diff --git a/src/telebt-v3.0/ao_pins.h b/src/telebt-v3.0/ao_pins.h index 1f7af41b..62dddf2a 100644 --- a/src/telebt-v3.0/ao_pins.h +++ b/src/telebt-v3.0/ao_pins.h @@ -80,6 +80,7 @@ #define HAS_TELEMETRY 0 #define HAS_APRS 0 #define HAS_ACCEL 0 +#define HAS_AES 1 #define HAS_SPI_1 1 #define SPI_1_PA5_PA6_PA7 1 /* CC1200 */ diff --git a/src/telebt-v3.0/ao_telebt.c b/src/telebt-v3.0/ao_telebt.c index 9117863b..8775d993 100644 --- a/src/telebt-v3.0/ao_telebt.c +++ b/src/telebt-v3.0/ao_telebt.c @@ -22,6 +22,7 @@ #include #include #include +#include #if HAS_SAMPLE_PROFILE #include #endif @@ -44,6 +45,8 @@ main(void) ao_btm_init(); ao_cmd_init(); + ao_lco_cmd_init(); + ao_eeprom_init(); ao_usb_init(); -- cgit v1.2.3 From d1ba276c6e54564f82920f65bf4c19df85c9ea56 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 19 Apr 2017 23:08:06 -0700 Subject: altos/telemini-v3.0: Update to production hardware Removed LEDs. Added USB. Flipped lots of pins around. This appears to make telemini work. Signed-off-by: Keith Packard --- src/telemini-v3.0/Makefile | 101 ++++++++++++++++++++++++++++++ src/telemini-v3.0/ao_pins.h | 38 +++-------- src/telemini-v3.0/ao_telemini.c | 5 +- src/telemini-v3.0/ao_telemini_calibrate.c | 80 ----------------------- 4 files changed, 114 insertions(+), 110 deletions(-) create mode 100644 src/telemini-v3.0/Makefile delete mode 100644 src/telemini-v3.0/ao_telemini_calibrate.c (limited to 'src') diff --git a/src/telemini-v3.0/Makefile b/src/telemini-v3.0/Makefile new file mode 100644 index 00000000..70c256f4 --- /dev/null +++ b/src/telemini-v3.0/Makefile @@ -0,0 +1,101 @@ +# +# AltOS build +# +# + +include ../stmf0/Makefile.defs + +INC = \ + ao.h \ + ao_arch.h \ + ao_arch_funcs.h \ + ao_pins.h \ + ao_product.h \ + ao_cc1200.h \ + ao_cc1200_CC1200.h \ + stm32f0.h + +# +# Common AltOS sources +# + +ALTOS_SRC = \ + ao_interrupt.c \ + ao_boot_chain.c \ + ao_romconfig.c \ + ao_product.c \ + ao_mutex.c \ + ao_panic.c \ + ao_stdio.c \ + ao_storage.c \ + ao_report.c \ + ao_ignite.c \ + ao_flight.c \ + ao_kalman.c \ + ao_sample.c \ + ao_data.c \ + ao_convert_pa.c \ + ao_convert_volt.c \ + ao_task.c \ + ao_log.c \ + ao_log_mini.c \ + ao_cmd.c \ + ao_config.c \ + ao_freq.c \ + ao_dma_stm.c \ + ao_timer.c \ + ao_exti_stm.c \ + ao_spi_stm.c \ + ao_adc_stm.c \ + ao_usb_stm.c \ + ao_m25.c \ + ao_ms5607.c \ + ao_cc1200.c \ + ao_telemetry.c \ + ao_packet_slave.c \ + ao_beep_stm.c \ + ao_packet.c + +PRODUCT=TeleMini-v3.0 +PRODUCT_DEF=-DTELEMINI_V_3_0 +IDPRODUCT=0x0027 + +CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -g -Os + +PROGNAME=telemini-v3.0 +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +CAL_ELF=$(PROGNAME)-cal-$(VERSION).elf +CAL_HEX=$(PROGNAME)-cal-$(VERSION).ihx + +SRC=$(ALTOS_SRC) ao_telemini.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Taltos.ld + +$(PROG): Makefile $(OBJ) altos-raw.ld + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +$(CAL_ELF): Makefile $(OBJ_CAL) altos-raw.ld + $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(CAL_ELF) $(OBJ_CAL) $(LIBS) + +ao_product.h: ao-make-product.5c ../Version + $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +$(OBJ) $(OBJ_CAL): $(INC) + +load: $(PROG) + lpc-load $(PROG) + +distclean: clean + +clean: + rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx + rm -f ao_product.h + +install: + +uninstall: diff --git a/src/telemini-v3.0/ao_pins.h b/src/telemini-v3.0/ao_pins.h index 7249ece7..351d28d8 100644 --- a/src/telemini-v3.0/ao_pins.h +++ b/src/telemini-v3.0/ao_pins.h @@ -18,12 +18,9 @@ #define HAS_BEEP 1 #define HAS_SERIAL_1 0 #define HAS_BATTERY_REPORT 1 -#define HAS_BOOT_LOADER 0 #define AO_STACK_SIZE 448 -#define RELOCATE_INTERRUPT 0 - #define IS_FLASH_LOADER 0 /* 48MHz clock based on 16MHz reference */ @@ -42,9 +39,10 @@ #define AO_APB_PRESCALER 1 #define AO_RCC_CFGR_PPRE_DIV STM_RCC_CFGR_PPRE_DIV_1 -#define HAS_USB 0 +#define HAS_USB 1 #define AO_USB_DIRECTIO 0 -#define AO_PA11_PA12_RMP 0 +#define AO_PA11_PA12_RMP 1 +#define AO_USB_FORCE_IDLE 1 #define PACKET_HAS_SLAVE 1 @@ -66,29 +64,13 @@ #define USE_INTERNAL_FLASH 0 #define HAS_IGNITE 1 #define HAS_IGNITE_REPORT 1 +#define AO_SMALL_ALTITUDE_TABLE 1 /* Beeper is on Tim1 CH3 */ -#define BEEPER_CHANNEL 3 -#define BEEPER_TIMER 1 +#define BEEPER_CHANNEL 4 +#define BEEPER_TIMER 2 #define BEEPER_PORT (&stm_gpioa) -#define BEEPER_PIN 10 - -/* LED */ -#define LED_PORT_ENABLE STM_RCC_AHBENR_IOPAEN -#define LED_PORT (&stm_gpioa) -#define LED_PIN_GREEN 15 -#define AO_LED_GREEN (1 << 15) -#define AO_LED_PANIC AO_LED_GREEN -#define AO_LED_LOW AO_LED_GREEN -#define AO_LED_MID AO_LED_GREEN - -#define LEDS_AVAILABLE AO_LED_GREEN - -/* Serial. Hooked to the spare pin (PA9/19) and the beeper (PA10/20) */ - -#define SERIAL_1_PA9_PA10 1 -#define USE_SERIAL_1_STDIN HAS_SERIAL_1 -#define DELAY_SERIAL_1_STDIN 0 +#define BEEPER_PIN 3 /* SPI */ @@ -101,16 +83,16 @@ #define M25_MAX_CHIPS 1 #define AO_M25_SPI_CS_PORT (&stm_gpioa) -#define AO_M25_SPI_CS_MASK (1 << 3) +#define AO_M25_SPI_CS_MASK (1 << 4) #define AO_M25_SPI_BUS AO_SPI_1_PA5_PA6_PA7 /* MS5607 */ #define HAS_MS5607 1 #define HAS_MS5611 0 -#define AO_MS5607_PRIVATE_PINS 0 +#define AO_MS5607_PRIVATE_PINS 1 #define AO_MS5607_CS_PORT (&stm_gpioa) -#define AO_MS5607_CS_PIN 4 +#define AO_MS5607_CS_PIN 15 #define AO_MS5607_CS_MASK (1 << AO_MS5607_CS_PIN) #define AO_MS5607_MISO_PORT (&stm_gpiob) #define AO_MS5607_MISO_PIN 4 diff --git a/src/telemini-v3.0/ao_telemini.c b/src/telemini-v3.0/ao_telemini.c index c2c13236..82c1acd4 100644 --- a/src/telemini-v3.0/ao_telemini.c +++ b/src/telemini-v3.0/ao_telemini.c @@ -23,8 +23,6 @@ main(void) { ao_clock_init(); ao_task_init(); - ao_led_init(LEDS_AVAILABLE); - ao_led_on(AO_LED_GREEN); ao_timer_init(); ao_dma_init(); @@ -38,6 +36,9 @@ main(void) #endif #if HAS_SERIAL_1 ao_serial_init(); +#endif +#if HAS_USB + ao_usb_init(); #endif ao_cmd_init(); diff --git a/src/telemini-v3.0/ao_telemini_calibrate.c b/src/telemini-v3.0/ao_telemini_calibrate.c deleted file mode 100644 index 461810f0..00000000 --- a/src/telemini-v3.0/ao_telemini_calibrate.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright © 2011 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; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include -#include - -static void -ao_cal(void) -{ - ao_config_get(); -#if HAS_BEEP - ao_beep_for(AO_BEEP_MID, AO_MS_TO_TICKS(500)); -#else - ao_led_for(AO_LED_MID, AO_MS_TO_TICKS(500)); -#endif - for (;;) { - ao_led_on(AO_LED_GREEN); - ao_radio_test_on(); - ao_delay(AO_SEC_TO_TICKS(30)); - ao_led_off(AO_LED_GREEN); - ao_radio_test_off(); - ao_delay(AO_SEC_TO_TICKS(5)); - } -} - -static struct ao_task ao_cal_task; - -void -main(void) -{ - ao_clock_init(); - ao_task_init(); - ao_led_init(LEDS_AVAILABLE); - ao_led_on(AO_LED_GREEN); - ao_timer_init(); - - ao_dma_init(); - ao_spi_init(); - ao_exti_init(); - -// ao_adc_init(); -#if HAS_BEEP - ao_beep_init(); -#endif -#if HAS_SERIAL_1 - ao_serial_init(); -#endif -// ao_cmd_init(); -// ao_ms5607_init(); - - ao_storage_init(); -// ao_flight_init(); -// ao_log_init(); -// ao_report_init(); -// ao_telemetry_init(); - - ao_radio_init(); -// ao_packet_slave_init(TRUE); -// ao_igniter_init(); - - ao_config_init(); - - ao_add_task(&ao_cal_task, ao_cal, "radio_cal"); - - ao_start_scheduler(); -} -- cgit v1.2.3 From 7db49a2052ec905cdc02f626c0933ca6889d64a4 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 19 Apr 2017 23:08:56 -0700 Subject: altos/telemini-v3.0: Add flash loader Now that telemini has USB, use the boot loader to make it easy to update firmware. Signed-off-by: Keith Packard --- src/telemini-v3.0/flash-loader/Makefile | 8 +++++++ src/telemini-v3.0/flash-loader/ao_pins.h | 37 ++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 src/telemini-v3.0/flash-loader/Makefile create mode 100644 src/telemini-v3.0/flash-loader/ao_pins.h (limited to 'src') diff --git a/src/telemini-v3.0/flash-loader/Makefile b/src/telemini-v3.0/flash-loader/Makefile new file mode 100644 index 00000000..8b628552 --- /dev/null +++ b/src/telemini-v3.0/flash-loader/Makefile @@ -0,0 +1,8 @@ +# +# AltOS flash loader build +# +# + +TOPDIR=../.. +HARDWARE=telemini-v3.0 +include $(TOPDIR)/stmf0/Makefile-flash.defs diff --git a/src/telemini-v3.0/flash-loader/ao_pins.h b/src/telemini-v3.0/flash-loader/ao_pins.h new file mode 100644 index 00000000..fea9a645 --- /dev/null +++ b/src/telemini-v3.0/flash-loader/ao_pins.h @@ -0,0 +1,37 @@ +/* + * Copyright © 2013 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#include + +/* beeper to 3.3V for boot loader mode */ + +#define AO_BOOT_PIN 1 +#define AO_BOOT_APPLICATION_GPIO stm_gpioa +#define AO_BOOT_APPLICATION_PIN 3 +#define AO_BOOT_APPLICATION_VALUE 0 +#define AO_BOOT_APPLICATION_MODE AO_EXTI_MODE_PULL_DOWN + +/* USB */ +#define HAS_USB 1 +#define AO_USB_DIRECTIO 0 +#define AO_PA11_PA12_RMP 1 + +#endif /* _AO_PINS_H_ */ -- cgit v1.2.3 From 51ce352d179835ca08e4cf9326e9e77d6b972fb7 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 21 Apr 2017 09:18:48 -0700 Subject: altos/lpc: Fix up Makefile definitions vpath reference to aes was busted. WARN_CFLAGS needs -Wcast-align. Wrap AO_CFLAGS. Signed-off-by: Keith Packard --- src/lpc/Makefile-lpc.defs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/lpc/Makefile-lpc.defs b/src/lpc/Makefile-lpc.defs index bccea5bc..be5ff3b7 100644 --- a/src/lpc/Makefile-lpc.defs +++ b/src/lpc/Makefile-lpc.defs @@ -4,7 +4,7 @@ endif include $(TOPDIR)/Makedefs -vpath % $(TOPDIR)/lpc:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR/aes):$(TOPDIR):$(TOPDIR)/math +vpath % $(TOPDIR)/lpc:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR/aes):$(TOPDIR):$(TOPDIR)/math:$(TOPDIR)/aes vpath make-altitude $(TOPDIR)/util vpath make-kalman $(TOPDIR)/util vpath kalman.5c $(TOPDIR)/kalman @@ -26,9 +26,12 @@ endif ELFTOHEX=$(TOPDIR)/../ao-tools/ao-elftohex/ao-elftohex CC=$(ARM_CC) -WARN_FLAGS=-Wall -Wextra -Werror +WARN_FLAGS=-Wall -Wextra -Werror -Wcast-align + +AO_CFLAGS=-I. -I$(TOPDIR)/lpc -I$(TOPDIR)/kernel -I$(TOPDIR)/drivers \ + -I$(TOPDIR)/product -I$(TOPDIR) -I$(TOPDIR)/math -I$(TOPDIR) \ + $(PDCLIB_INCLUDES) -AO_CFLAGS=-I. -I$(TOPDIR)/lpc -I$(TOPDIR)/kernel -I$(TOPDIR)/drivers -I$(TOPDIR)/product -I$(TOPDIR) -I$(TOPDIR)/math -I$(TOPDIR) $(PDCLIB_INCLUDES) LPC_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m0 -mthumb\ -ffreestanding -nostdlib $(AO_CFLAGS) $(WARN_FLAGS) -- cgit v1.2.3 From adb842b64b04a7d70e543bad7ae59807d549e85a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 21 Apr 2017 16:40:58 -0700 Subject: altos/lpc: Add (void *) cast to fix alignment warning The -Wcast-align warning is generated when this cast is not present. Signed-off-by: Keith Packard --- src/lpc/ao_arch_funcs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lpc/ao_arch_funcs.h b/src/lpc/ao_arch_funcs.h index 5fc0f680..15106dea 100644 --- a/src/lpc/ao_arch_funcs.h +++ b/src/lpc/ao_arch_funcs.h @@ -109,7 +109,7 @@ ao_arch_memory_barrier() { static inline void ao_arch_init_stack(struct ao_task *task, void *start) { - uint32_t *sp = (uint32_t *) (task->stack + AO_STACK_SIZE); + uint32_t *sp = (uint32_t *) (void *) (task->stack + AO_STACK_SIZE); uint32_t a = (uint32_t) start; int i; -- cgit v1.2.3 From 77c76e429074a53c1c5230a7b5e665d1715b296f Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 21 Apr 2017 17:04:28 -0700 Subject: altos/telemini-v3.0: Remove vestiges of the pre-USB code Pre-USB telemini v3 designs had a separate firmware load for radio calibration. Now that we've got enough USB to perform flash/cal/test, we don't need that other firmware load, so we can remove the remaining Makefile remnants of the calibration load. Signed-off-by: Keith Packard --- src/telemini-v3.0/Makefile | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/telemini-v3.0/Makefile b/src/telemini-v3.0/Makefile index 70c256f4..4713b3ad 100644 --- a/src/telemini-v3.0/Makefile +++ b/src/telemini-v3.0/Makefile @@ -66,26 +66,18 @@ PROGNAME=telemini-v3.0 PROG=$(PROGNAME)-$(VERSION).elf HEX=$(PROGNAME)-$(VERSION).ihx -CAL_ELF=$(PROGNAME)-cal-$(VERSION).elf -CAL_HEX=$(PROGNAME)-cal-$(VERSION).ihx - SRC=$(ALTOS_SRC) ao_telemini.c OBJ=$(SRC:.c=.o) all: $(PROG) $(HEX) -LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Taltos.ld - -$(PROG): Makefile $(OBJ) altos-raw.ld +$(PROG): Makefile $(OBJ) $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) -$(CAL_ELF): Makefile $(OBJ_CAL) altos-raw.ld - $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(CAL_ELF) $(OBJ_CAL) $(LIBS) - ao_product.h: ao-make-product.5c ../Version $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ -$(OBJ) $(OBJ_CAL): $(INC) +$(OBJ): $(INC) load: $(PROG) lpc-load $(PROG) -- cgit v1.2.3 From 64ac93f5495db7a8b06f1eb4fe4eb2418125d792 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 21 Apr 2017 17:06:23 -0700 Subject: altos/lpc,altos/stmf0: Use -n flag to work around link editor issue Something changed in the link editor which makes it complain about 'no space for program headers' on LPC and STMF0 builds. Somehow, adding the '-n' flag to the linking step fixes it. It doesn't appear to break the build, so I guess it's ok? Signed-off-by: Keith Packard --- src/lpc/Makefile.defs | 2 +- src/stmf0/Makefile.defs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lpc/Makefile.defs b/src/lpc/Makefile.defs index b6d739c2..5bb8133d 100644 --- a/src/lpc/Makefile.defs +++ b/src/lpc/Makefile.defs @@ -5,7 +5,7 @@ endif include $(TOPDIR)/lpc/Makefile-lpc.defs include $(TOPDIR)/Makedefs -LDFLAGS=$(CFLAGS) -L$(TOPDIR)/lpc -Wl,-Taltos.ld +LDFLAGS=$(CFLAGS) -L$(TOPDIR)/lpc -Wl,-Taltos.ld -n ao_serial_lpc.h: $(TOPDIR)/lpc/baud_rate ao_pins.h nickle $(TOPDIR)/lpc/baud_rate `awk '/AO_LPC_CLKOUT/{print $$3}' ao_pins.h` > $@ diff --git a/src/stmf0/Makefile.defs b/src/stmf0/Makefile.defs index a1d93eb5..3da42874 100644 --- a/src/stmf0/Makefile.defs +++ b/src/stmf0/Makefile.defs @@ -4,6 +4,6 @@ endif include $(TOPDIR)/stmf0/Makefile-stmf0.defs -LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Taltos.ld +LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Taltos.ld -n .DEFAULT_GOAL=all -- cgit v1.2.3 From 86a54146b58be86c58fb45386c7abcfa0bb11677 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 21 Apr 2017 17:15:05 -0700 Subject: alots/stmf0: Fix vpath entry for AES directory Mis-placed ) Signed-off-by: Keith Packard --- src/stmf0/Makefile-stmf0.defs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/stmf0/Makefile-stmf0.defs b/src/stmf0/Makefile-stmf0.defs index 2ea3d1d8..f2c53499 100644 --- a/src/stmf0/Makefile-stmf0.defs +++ b/src/stmf0/Makefile-stmf0.defs @@ -4,7 +4,7 @@ endif include $(TOPDIR)/Makedefs -vpath % $(TOPDIR)/stmf0:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR/aes):$(TOPDIR):$(TOPDIR)/math:$(TOPDIR)/lisp +vpath % $(TOPDIR)/stmf0:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR)/aes:$(TOPDIR):$(TOPDIR)/math:$(TOPDIR)/lisp vpath make-altitude $(TOPDIR)/util vpath make-kalman $(TOPDIR)/util vpath kalman.5c $(TOPDIR)/kalman -- cgit v1.2.3 From 5849ee6c09669e6d2e6940a76bcb5cc23178fc68 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 21 Apr 2017 21:32:26 -0700 Subject: altos/lpc: Really fix aes entry in lpc vpath I added another entry instead of fixing the existing one. Not ideal. Signed-off-by: Keith Packard --- src/lpc/Makefile-lpc.defs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lpc/Makefile-lpc.defs b/src/lpc/Makefile-lpc.defs index be5ff3b7..c4521620 100644 --- a/src/lpc/Makefile-lpc.defs +++ b/src/lpc/Makefile-lpc.defs @@ -4,7 +4,7 @@ endif include $(TOPDIR)/Makedefs -vpath % $(TOPDIR)/lpc:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR/aes):$(TOPDIR):$(TOPDIR)/math:$(TOPDIR)/aes +vpath % $(TOPDIR)/lpc:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR)/aes:$(TOPDIR):$(TOPDIR)/math vpath make-altitude $(TOPDIR)/util vpath make-kalman $(TOPDIR)/util vpath kalman.5c $(TOPDIR)/kalman -- cgit v1.2.3 From 4682323a4bf147b9a908f5f9104bf01ab2cf0533 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 21 Apr 2017 23:02:57 -0700 Subject: altos/stmf0: Pull beeper pin low when beeper is off This avoids having the pin float and pick up noise from any adjacent signals, like TeleMini's radio. Signed-off-by: Keith Packard --- src/stmf0/ao_beep_stm.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/stmf0/ao_beep_stm.c b/src/stmf0/ao_beep_stm.c index 84ccd93e..610f4a31 100644 --- a/src/stmf0/ao_beep_stm.c +++ b/src/stmf0/ao_beep_stm.c @@ -55,6 +55,9 @@ disable(void) timer.bdtr = 0; #endif stm_rcc_enr &= ~(1 << STM_RCC_TIMER); + + /* Disconnect the timer from the pin */ + stm_afr_set(BEEPER_PORT, BEEPER_PIN, STM_AFR_NONE); } void @@ -361,6 +364,9 @@ ao_beep(uint8_t beep) /* Update the values */ timer.egr = (1 << STM_TIM23_EGR_UG); + + /* Hook the timer up to the beeper pin */ + stm_afr_set(BEEPER_PORT, BEEPER_PIN, STM_AFR_AF2); #endif } } @@ -376,8 +382,7 @@ ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant void ao_beep_init(void) { - ao_enable_port(BEEPER_PORT); - stm_afr_set(BEEPER_PORT, BEEPER_PIN, STM_AFR_AF2); + ao_enable_output(BEEPER_PORT, BEEPER_PIN, BEEPER, 0); /* Leave the timer off until requested */ stm_rcc_enr &= ~(1 << STM_RCC_TIMER); -- cgit v1.2.3 From ffc90fa3f932aef4dd85147817949aa9474b6d26 Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Sat, 22 Apr 2017 11:38:08 -0600 Subject: fix TeleFireTwo product name in ao-list output --- src/telefiretwo-v1.0/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/telefiretwo-v1.0/Makefile b/src/telefiretwo-v1.0/Makefile index 0a2f9b58..927b3a80 100644 --- a/src/telefiretwo-v1.0/Makefile +++ b/src/telefiretwo-v1.0/Makefile @@ -55,7 +55,7 @@ ALTOS_SRC = \ PRODUCT_SRC = \ ao_telefiretwo.c -PRODUCT=TeleFire-v1.0 +PRODUCT=TeleFireTwo-v1.0 PRODUCT_DEF=-DTELEFIRETWO_V_1_0 IDPRODUCT=0x000f -- cgit v1.2.3 From 439a51ed503b74c1739cf150cdc91685653deed0 Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Sat, 22 Apr 2017 15:45:52 -0600 Subject: enable spi flash on telefiretwo --- src/telefiretwo-v1.0/Makefile | 2 ++ src/telefiretwo-v1.0/ao_pins.h | 9 +++++++++ src/telefiretwo-v1.0/ao_telefiretwo.c | 2 ++ 3 files changed, 13 insertions(+) (limited to 'src') diff --git a/src/telefiretwo-v1.0/Makefile b/src/telefiretwo-v1.0/Makefile index 927b3a80..f4629599 100644 --- a/src/telefiretwo-v1.0/Makefile +++ b/src/telefiretwo-v1.0/Makefile @@ -43,6 +43,8 @@ ALTOS_SRC = \ ao_spi_stm.c \ ao_beep_stm.c \ ao_eeprom_stm.c \ + ao_storage.c \ + ao_m25.c \ ao_usb_stm.c \ ao_exti_stm.c \ ao_cc1200.c \ diff --git a/src/telefiretwo-v1.0/ao_pins.h b/src/telefiretwo-v1.0/ao_pins.h index 8cde0043..aa8501c0 100644 --- a/src/telefiretwo-v1.0/ao_pins.h +++ b/src/telefiretwo-v1.0/ao_pins.h @@ -99,6 +99,15 @@ #define FAST_TIMER_FREQ 10000 /* .1ms for debouncing */ +/* + * SPI Flash memory + */ + +#define M25_MAX_CHIPS 1 +#define AO_M25_SPI_CS_PORT (&stm_gpioa) +#define AO_M25_SPI_CS_MASK (1 << 15) +#define AO_M25_SPI_BUS AO_SPI_2_PB13_PB14_PB15 + /* * Radio is a cc1200 connected via SPI */ diff --git a/src/telefiretwo-v1.0/ao_telefiretwo.c b/src/telefiretwo-v1.0/ao_telefiretwo.c index bdcf3213..fa7b7679 100644 --- a/src/telefiretwo-v1.0/ao_telefiretwo.c +++ b/src/telefiretwo-v1.0/ao_telefiretwo.c @@ -20,6 +20,7 @@ #include #include #include +#include void main(void) @@ -40,6 +41,7 @@ main(void) ao_adc_init(); ao_eeprom_init(); + ao_storage_init(); ao_radio_init(); -- cgit v1.2.3 From 359e2d6eca5258f4fabc59772f1320e195a7397c Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Sat, 22 Apr 2017 16:36:18 -0600 Subject: fleshing out logging for telefiretwo --- src/kernel/ao_log.h | 27 ++++++++ src/kernel/ao_log_firetwo.c | 155 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 src/kernel/ao_log_firetwo.c (limited to 'src') diff --git a/src/kernel/ao_log.h b/src/kernel/ao_log.h index ad28e5ca..a2f2c6ca 100644 --- a/src/kernel/ao_log.h +++ b/src/kernel/ao_log.h @@ -52,6 +52,7 @@ extern __pdata enum ao_flight_state ao_log_state; #define AO_LOG_FORMAT_TELEMEGA 10 /* 32 byte typed telemega records with 32 bit gyro cal */ #define AO_LOG_FORMAT_DETHERM 11 /* 16-byte MS5607 baro only, no ADC */ #define AO_LOG_FORMAT_TELEMINI3 12 /* 16-byte MS5607 baro only, 3.3V supply, stm32f042 SoC */ +#define AO_LOG_FORMAT_TELEFIRETWO 13 /* 32-byte test stand data */ #define AO_LOG_FORMAT_NONE 127 /* No log at all */ extern __code uint8_t ao_log_format; @@ -300,6 +301,32 @@ struct ao_log_mega { ((l)->u.gps.altitude_high = (a) >> 16), \ (l)->u.gps.altitude_low = (a)) +struct ao_log_firetwo { + char type; /* 0 */ + uint8_t csum; /* 1 */ + uint16_t tick; /* 2 */ + union { /* 4 */ + /* AO_LOG_FLIGHT */ + struct { + uint16_t flight; /* 4 */ + uint16_t idle_pressure; /* 6 */ + uint16_t idle_thrust; /* 8 */ + } flight; /* 16 */ + /* AO_LOG_STATE */ + struct { + uint16_t state; /* 4 */ + uint16_t reason; /* 6 */ + } state; /* 8 */ + /* AO_LOG_SENSOR */ + struct { + uint16_t pressure; /* 4 */ + uint16_t thrust; /* 6 */ + uint16_t thermistor[4]; /* 8 */ + } sensor; /* 24 */ + uint8_t align[28]; /* 4 */ + } u; /* 32 */ +}; + struct ao_log_metrum { char type; /* 0 */ uint8_t csum; /* 1 */ diff --git a/src/kernel/ao_log_firetwo.c b/src/kernel/ao_log_firetwo.c new file mode 100644 index 00000000..71e84dfe --- /dev/null +++ b/src/kernel/ao_log_firetwo.c @@ -0,0 +1,155 @@ +/* + * Copyright © 2017 Bdale Garbee + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" +#include +#include +#include + +static __xdata struct ao_log_firetwo log; + +__code uint8_t ao_log_format = AO_LOG_FORMAT_TELEFIRETWO; + +static uint8_t +ao_log_csum(__xdata uint8_t *b) __reentrant +{ + uint8_t sum = 0x5a; + uint8_t i; + + for (i = 0; i < sizeof (struct ao_log_firetwo); i++) + sum += *b++; + return -sum; +} + +uint8_t +ao_log_firetwo(__xdata struct ao_log_firetwo *log) __reentrant +{ + uint8_t wrote = 0; + /* set checksum */ + log->csum = 0; + log->csum = ao_log_csum((__xdata uint8_t *) log); + ao_mutex_get(&ao_log_mutex); { + if (ao_log_current_pos >= ao_log_end_pos && ao_log_running) + ao_log_stop(); + if (ao_log_running) { + wrote = 1; + ao_storage_write(ao_log_current_pos, + log, + sizeof (struct ao_log_firetwo)); + ao_log_current_pos += sizeof (struct ao_log_firetwo); + } + } ao_mutex_put(&ao_log_mutex); + return wrote; +} + +static uint8_t +ao_log_dump_check_data(void) +{ + if (ao_log_csum((uint8_t *) &log) != 0) + return 0; + return 1; +} + +#if HAS_ADC +static __data uint8_t ao_log_data_pos; + +/* a hack to make sure that ao_log_metrums fill the eeprom block in even units */ +typedef uint8_t check_log_size[1-(256 % sizeof(struct ao_log_firetwo))] ; +#endif + +void +ao_log(void) +{ + __pdata uint16_t next_sensor, next_other; + + ao_storage_setup(); + + ao_log_scan(); + + while (!ao_log_running) + ao_sleep(&ao_log_running); + +#if HAS_FLIGHT + log.type = AO_LOG_FLIGHT; + log.tick = ao_sample_tick; + log.u.flight.idle_pressure = ao_idle_pressure; + log.u.flight.idle_thrust = ao_idle_thrust; + log.u.flight.flight = ao_flight_number; + ao_log_firetwo(&log); +#endif + + /* Write the whole contents of the ring to the log + * when starting up. + */ + ao_log_data_pos = ao_data_ring_next(ao_data_head); + next_other = next_sensor = ao_data_ring[ao_log_data_pos].tick; + ao_log_state = ao_flight_startup; + for (;;) { + /* Write samples to EEPROM */ + while (ao_log_data_pos != ao_data_head) { + log.tick = ao_data_ring[ao_log_data_pos].tick; + if ((int16_t) (log.tick - next_sensor) >= 0) { + log.type = AO_LOG_SENSOR; + log.u.sensor.pressure = ao_data_ring[ao_log_data_pos].sensor.pressure; + log.u.sensor.thrust = ao_data_ring[ao_log_data_pos].sensor.thrust; + for (i = 0; i < 4; i++) { + log.u.sensor.thermistor[i] = ao_data_ring[ao_log_data_pos].sensor.thermistor[i]; + } + ao_log_firetwo(&log); + } + ao_log_data_pos = ao_data_ring_next(ao_log_data_pos); + } +#if HAS_FLIGHT + /* Write state change to EEPROM */ + if (ao_flight_state != ao_log_state) { + ao_log_state = ao_flight_state; + log.type = AO_LOG_STATE; + log.tick = ao_time(); + log.u.state.state = ao_log_state; + log.u.state.reason = 0; + ao_log_firetwo(&log); + + if (ao_log_state == ao_flight_landed) + ao_log_stop(); + } +#endif + + ao_log_flush(); + + /* Wait for a while */ + ao_delay(AO_MS_TO_TICKS(100)); + + /* Stop logging when told to */ + while (!ao_log_running) + ao_sleep(&ao_log_running); + } +} +#endif + +uint16_t +ao_log_flight(uint8_t slot) +{ + if (!ao_storage_read(ao_log_pos(slot), + &log, + sizeof (struct ao_log_firetwo))) + return 0; + + if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT) + return log.u.flight.flight; + return 0; +} -- cgit v1.2.3 From db12c17e9538bd82f2c2bf21357887ee7d894a1c Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Sat, 22 Apr 2017 16:59:03 -0600 Subject: a stab at turning on rudimentary logging for telefiretwo --- src/kernel/ao_log_firetwo.c | 28 +++++++++++----------------- src/telefiretwo-v1.0/Makefile | 5 ++++- src/telefiretwo-v1.0/ao_pins.h | 2 ++ 3 files changed, 17 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/kernel/ao_log_firetwo.c b/src/kernel/ao_log_firetwo.c index 71e84dfe..46559206 100644 --- a/src/kernel/ao_log_firetwo.c +++ b/src/kernel/ao_log_firetwo.c @@ -75,7 +75,9 @@ typedef uint8_t check_log_size[1-(256 % sizeof(struct ao_log_firetwo))] ; void ao_log(void) { - __pdata uint16_t next_sensor, next_other; + uint16_t ao_idle_pressure = 0; // write code to capture pre-test values someday + uint16_t ao_idle_thrust = 0; + uint16_t ao_flight_state = ao_flight_startup; ao_storage_setup(); @@ -84,37 +86,31 @@ ao_log(void) while (!ao_log_running) ao_sleep(&ao_log_running); -#if HAS_FLIGHT log.type = AO_LOG_FLIGHT; - log.tick = ao_sample_tick; + log.tick = ao_time(); log.u.flight.idle_pressure = ao_idle_pressure; log.u.flight.idle_thrust = ao_idle_thrust; log.u.flight.flight = ao_flight_number; ao_log_firetwo(&log); -#endif /* Write the whole contents of the ring to the log * when starting up. */ ao_log_data_pos = ao_data_ring_next(ao_data_head); - next_other = next_sensor = ao_data_ring[ao_log_data_pos].tick; ao_log_state = ao_flight_startup; for (;;) { /* Write samples to EEPROM */ while (ao_log_data_pos != ao_data_head) { log.tick = ao_data_ring[ao_log_data_pos].tick; - if ((int16_t) (log.tick - next_sensor) >= 0) { - log.type = AO_LOG_SENSOR; - log.u.sensor.pressure = ao_data_ring[ao_log_data_pos].sensor.pressure; - log.u.sensor.thrust = ao_data_ring[ao_log_data_pos].sensor.thrust; - for (i = 0; i < 4; i++) { - log.u.sensor.thermistor[i] = ao_data_ring[ao_log_data_pos].sensor.thermistor[i]; - } - ao_log_firetwo(&log); - } + log.type = AO_LOG_SENSOR; + log.u.sensor.pressure = ao_data_ring[ao_log_data_pos].adc.pressure; + log.u.sensor.thrust = ao_data_ring[ao_log_data_pos].adc.thrust; +// for (i = 0; i < 4; i++) { +// log.u.sensor.thermistor[i] = ao_data_ring[ao_log_data_pos].sensor.thermistor[i]; +// } + ao_log_firetwo(&log); ao_log_data_pos = ao_data_ring_next(ao_log_data_pos); } -#if HAS_FLIGHT /* Write state change to EEPROM */ if (ao_flight_state != ao_log_state) { ao_log_state = ao_flight_state; @@ -127,7 +123,6 @@ ao_log(void) if (ao_log_state == ao_flight_landed) ao_log_stop(); } -#endif ao_log_flush(); @@ -139,7 +134,6 @@ ao_log(void) ao_sleep(&ao_log_running); } } -#endif uint16_t ao_log_flight(uint8_t slot) diff --git a/src/telefiretwo-v1.0/Makefile b/src/telefiretwo-v1.0/Makefile index f4629599..87d5d477 100644 --- a/src/telefiretwo-v1.0/Makefile +++ b/src/telefiretwo-v1.0/Makefile @@ -7,6 +7,7 @@ include ../stm/Makefile.defs INC = \ ao.h \ ao_pins.h \ + ao_log.h \ ao_arch.h \ ao_arch_funcs.h \ ao_pad.h \ @@ -52,7 +53,9 @@ ALTOS_SRC = \ ao_aes.c \ ao_aes_tables.c \ ao_pad.c \ - ao_radio_cmac_cmd.c + ao_radio_cmac_cmd.c \ + ao_log.c \ + ao_log_firetwo.c PRODUCT_SRC = \ ao_telefiretwo.c diff --git a/src/telefiretwo-v1.0/ao_pins.h b/src/telefiretwo-v1.0/ao_pins.h index aa8501c0..95189cdc 100644 --- a/src/telefiretwo-v1.0/ao_pins.h +++ b/src/telefiretwo-v1.0/ao_pins.h @@ -41,6 +41,8 @@ #define AO_DATA_RING 32 #define HAS_FIXED_PAD_BOX 1 +#define LOG_ERASE_MARK 0x55 + /* 8MHz High speed external crystal */ #define AO_HSE 8000000 -- cgit v1.2.3 From e05b281e6d1a7a4fa92d52f2491f27266045df96 Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Sat, 22 Apr 2017 17:20:41 -0600 Subject: cobble up a command to toggle logging on/off on TeleFireTwo --- src/telefiretwo-v1.0/ao_telefiretwo.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src') diff --git a/src/telefiretwo-v1.0/ao_telefiretwo.c b/src/telefiretwo-v1.0/ao_telefiretwo.c index fa7b7679..115b3e91 100644 --- a/src/telefiretwo-v1.0/ao_telefiretwo.c +++ b/src/telefiretwo-v1.0/ao_telefiretwo.c @@ -17,11 +17,25 @@ */ #include +#include #include #include #include #include +static void +set_logging(void) +{ + ao_cmd_hex(); + ao_log_running = ao_cmd_lex_i; + ao_wakeup(&ao_log_running); +} + +__code struct ao_cmds ao_firetwo_cmds[] = { + { set_logging, "L <0 off, 1 on>\0Log sensors to flash" }, + { 0, NULL }, +}; + void main(void) { @@ -36,12 +50,14 @@ main(void) ao_dma_init(); ao_exti_init(); + ao_cmd_register(&ao_firetwo_cmds[0]); ao_cmd_init(); ao_adc_init(); ao_eeprom_init(); ao_storage_init(); + ao_log_init(); ao_radio_init(); -- cgit v1.2.3 From e5e0ce18b2ae684896a6d7d0a4c10269199d95b5 Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Sat, 22 Apr 2017 23:01:26 -0600 Subject: enable logging support in telefiretwo --- src/telefiretwo-v1.0/ao_pins.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/telefiretwo-v1.0/ao_pins.h b/src/telefiretwo-v1.0/ao_pins.h index 95189cdc..b2f5a5ab 100644 --- a/src/telefiretwo-v1.0/ao_pins.h +++ b/src/telefiretwo-v1.0/ao_pins.h @@ -32,9 +32,9 @@ #define HAS_ADC 1 #define HAS_DBG 0 #define HAS_EEPROM 1 -#define HAS_LOG 0 +#define HAS_LOG 1 #define HAS_PAD 1 -#define USE_INTERNAL_FLASH 1 +#define USE_INTERNAL_FLASH 0 #define IGNITE_ON_P0 0 #define PACKET_HAS_MASTER 0 #define PACKET_HAS_SLAVE 0 @@ -69,7 +69,6 @@ #define AO_RCC_CFGR_PPRE2_DIV STM_RCC_CFGR_PPRE2_DIV_2 #define HAS_EEPROM 1 -#define USE_INTERNAL_FLASH 1 #define USE_EEPROM_CONFIG 1 #define USE_STORAGE_CONFIG 0 #define HAS_USB 1 -- cgit v1.2.3 From e3b30d4bd6faf68c885791fb87229558cc1157a6 Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Sat, 22 Apr 2017 23:01:44 -0600 Subject: add static test start and stop commands to radio protocol for telefiretwo --- src/drivers/ao_pad.c | 31 ++++++++++++++++++++++++++++--- src/drivers/ao_pad.h | 5 +++++ 2 files changed, 33 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_pad.c b/src/drivers/ao_pad.c index ffa833fe..28c00fe3 100644 --- a/src/drivers/ao_pad.c +++ b/src/drivers/ao_pad.c @@ -316,7 +316,7 @@ ao_pad(void) command.tick, command.box, ao_pad_box, command.cmd, command.channels); switch (command.cmd) { - case AO_LAUNCH_ARM: + case AO_PAD_ARM: if (command.box != ao_pad_box) { PRINTD ("box number mismatch\n"); break; @@ -338,7 +338,7 @@ ao_pad(void) ao_pad_arm_time = ao_time(); break; - case AO_LAUNCH_QUERY: + case AO_PAD_QUERY: if (command.box != ao_pad_box) { PRINTD ("box number mismatch\n"); break; @@ -357,7 +357,7 @@ ao_pad(void) query.igniter_status[3]); ao_radio_cmac_send(&query, sizeof (query)); break; - case AO_LAUNCH_FIRE: + case AO_PAD_FIRE: if (!ao_pad_armed) { PRINTD ("not armed\n"); break; @@ -373,6 +373,31 @@ ao_pad(void) ao_wakeup(&ao_pad_ignite); break; } + case AO_PAD_STATIC: + if (!ao_pad_armed) { + PRINTD ("not armed\n"); + break; + } +#ifdef HAS_LOG + if (!ao_log_running) ao_log_start(); +#endif + if ((uint16_t) (ao_time() - ao_pad_arm_time) > AO_SEC_TO_TICKS(20)) { + PRINTD ("late pad arm_time %d time %d\n", + ao_pad_arm_time, ao_time()); + break; + } + PRINTD ("ignite\n"); + ao_pad_ignite = ao_pad_armed; + ao_pad_arm_time = ao_time(); + ao_wakeup(&ao_pad_ignite); + break; + } + case AO_PAD_ENDSTATIC: +#ifdef HAS_LOG + ao_log_stop(); +#endif + break; + } } } diff --git a/src/drivers/ao_pad.h b/src/drivers/ao_pad.h index 648d3005..e4115222 100644 --- a/src/drivers/ao_pad.h +++ b/src/drivers/ao_pad.h @@ -54,6 +54,11 @@ struct ao_pad_query { */ #define AO_PAD_FIRE 3 +/* Fire current armed pads for 200ms, no report, logging test stand sensors + */ +#define AO_PAD_STATIC 4 +#define AO_PAD_ENDSTATIC 5 + #define AO_PAD_FIRE_TIME AO_MS_TO_TICKS(200) #define AO_PAD_ARM_STATUS_DISARMED 0 -- cgit v1.2.3 From 6cfd9411026d536b5b75098b8c9ec3ceb3d945aa Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Sat, 22 Apr 2017 23:02:53 -0600 Subject: eliminate spurious close braces --- src/drivers/ao_pad.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_pad.c b/src/drivers/ao_pad.c index 28c00fe3..c18cdd8d 100644 --- a/src/drivers/ao_pad.c +++ b/src/drivers/ao_pad.c @@ -372,7 +372,6 @@ ao_pad(void) ao_pad_arm_time = ao_time(); ao_wakeup(&ao_pad_ignite); break; - } case AO_PAD_STATIC: if (!ao_pad_armed) { PRINTD ("not armed\n"); @@ -391,7 +390,6 @@ ao_pad(void) ao_pad_arm_time = ao_time(); ao_wakeup(&ao_pad_ignite); break; - } case AO_PAD_ENDSTATIC: #ifdef HAS_LOG ao_log_stop(); -- cgit v1.2.3 From d75351c5a07241bcbb951758796b4f639ace6b1f Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Sat, 22 Apr 2017 23:42:23 -0600 Subject: implement static test start and stop protocol for telefiretwo+telebt --- src/drivers/ao_lco.c | 2 +- src/drivers/ao_lco_cmd.c | 51 +++++++++++++++++++++++++++++++++++++++++++---- src/drivers/ao_lco_func.c | 8 ++++---- src/drivers/ao_lco_func.h | 2 +- src/drivers/ao_lco_two.c | 2 +- 5 files changed, 54 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_lco.c b/src/drivers/ao_lco.c index 00f10ecc..e1806ca3 100644 --- a/src/drivers/ao_lco.c +++ b/src/drivers/ao_lco.c @@ -661,7 +661,7 @@ ao_lco_monitor(void) ao_lco_armed, ao_lco_firing); if (ao_lco_armed && ao_lco_firing) { - ao_lco_ignite(); + ao_lco_ignite(AO_PAD_FIRE); } else { ao_lco_update(); if (ao_lco_armed) { diff --git a/src/drivers/ao_lco_cmd.c b/src/drivers/ao_lco_cmd.c index dcc0c6d0..8de21fb6 100644 --- a/src/drivers/ao_lco_cmd.c +++ b/src/drivers/ao_lco_cmd.c @@ -61,9 +61,9 @@ lco_arm(void) } static void -lco_ignite(void) +lco_ignite(uint8_t cmd) { - ao_lco_ignite(); + ao_lco_ignite(cmd); } static void @@ -145,7 +145,40 @@ lco_fire_cmd(void) __reentrant secs = 100; for (i = 0; i < secs; i++) { printf("fire %d\n", i); flush(); - lco_ignite(); + lco_ignite(AO_PAD_FIRE); + ao_delay(AO_MS_TO_TICKS(100)); + } +} + +static void +lco_static_cmd(void) __reentrant +{ + uint8_t secs; + uint8_t i; + int8_t r; + + lco_args(); + ao_cmd_decimal(); + secs = ao_cmd_lex_i; + if (ao_cmd_status != ao_cmd_success) + return; + r = lco_query(); + if (r != AO_RADIO_CMAC_OK) { + printf("query failed %d\n", r); + return; + } + + for (i = 0; i < 4; i++) { + printf("arm %d\n", i); flush(); + lco_arm(); + } + + secs = secs * 10 - 5; + if (secs > 100) + secs = 100; + for (i = 0; i < secs; i++) { + printf("fire %d\n", i); flush(); + lco_ignite(AO_PAD_STATIC); ao_delay(AO_MS_TO_TICKS(100)); } } @@ -171,12 +204,22 @@ lco_ignite_cmd(void) __reentrant uint8_t i; lco_args(); for (i = 0; i < 4; i++) - lco_ignite(); + lco_ignite(AO_PAD_FIRE); +} + + +static void +lco_endstatic_cmd(void) __reentrant +{ + lco_ignite(AO_PAD_ENDSTATIC); } static __code struct ao_cmds ao_lco_cmds[] = { { lco_report_cmd, "l \0Get remote status" }, { lco_fire_cmd, "F \0Fire remote igniters" }, + { lco_fire_cmd, "F \0Fire remote igniters" }, + { lco_static_cmd, "S \0Initiate static test" }, + { lco_endstatic_cmd, "D\0End static test (and download someday)" }, { lco_arm_cmd, "a \0Arm remote igniter" }, { lco_ignite_cmd, "i \0Pulse remote igniter" }, { 0, NULL }, diff --git a/src/drivers/ao_lco_func.c b/src/drivers/ao_lco_func.c index 862cb1be..92b344ed 100644 --- a/src/drivers/ao_lco_func.c +++ b/src/drivers/ao_lco_func.c @@ -47,7 +47,7 @@ ao_lco_query(uint16_t box, struct ao_pad_query *query, uint16_t *tick_offset) ao_mutex_get(&ao_lco_mutex); command.tick = ao_time(); command.box = box; - command.cmd = AO_LAUNCH_QUERY; + command.cmd = AO_PAD_QUERY; command.channels = 0; ao_radio_cmac_send(&command, sizeof (command)); sent_time = ao_time(); @@ -64,19 +64,19 @@ ao_lco_arm(uint16_t box, uint8_t channels, uint16_t tick_offset) ao_mutex_get(&ao_lco_mutex); command.tick = ao_time() - tick_offset; command.box = box; - command.cmd = AO_LAUNCH_ARM; + command.cmd = AO_PAD_ARM; command.channels = channels; ao_radio_cmac_send(&command, sizeof (command)); ao_mutex_put(&ao_lco_mutex); } void -ao_lco_ignite(void) +ao_lco_ignite(uint8_t cmd) { ao_mutex_get(&ao_lco_mutex); command.tick = 0; command.box = 0; - command.cmd = AO_LAUNCH_FIRE; + command.cmd = cmd; command.channels = 0; ao_radio_cmac_send(&command, sizeof (command)); ao_mutex_put(&ao_lco_mutex); diff --git a/src/drivers/ao_lco_func.h b/src/drivers/ao_lco_func.h index 6b06f928..9d4a27ba 100644 --- a/src/drivers/ao_lco_func.h +++ b/src/drivers/ao_lco_func.h @@ -28,6 +28,6 @@ void ao_lco_arm(uint16_t box, uint8_t channels, uint16_t tick_offset); void -ao_lco_ignite(void); +ao_lco_ignite(uint8_t cmd); #endif /* _AO_LCO_FUNC_H_ */ diff --git a/src/drivers/ao_lco_two.c b/src/drivers/ao_lco_two.c index 1cb0546c..e2f86745 100644 --- a/src/drivers/ao_lco_two.c +++ b/src/drivers/ao_lco_two.c @@ -287,7 +287,7 @@ ao_lco_monitor(void) ao_lco_armed, ao_lco_firing); if (ao_lco_armed && ao_lco_firing) { - ao_lco_ignite(); + ao_lco_ignite(AO_PAD_FIRE); } else { ao_lco_get_channels(); if (ao_lco_armed) { -- cgit v1.2.3 From cd291d38b92b31c3612e6de6cdf4e5988fc01c12 Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Sun, 23 Apr 2017 00:02:47 -0600 Subject: allow multiple tests to be logged on telefiretwo without rebooting --- src/kernel/ao_log_firetwo.c | 100 ++++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 50 deletions(-) (limited to 'src') diff --git a/src/kernel/ao_log_firetwo.c b/src/kernel/ao_log_firetwo.c index 46559206..4b42abe4 100644 --- a/src/kernel/ao_log_firetwo.c +++ b/src/kernel/ao_log_firetwo.c @@ -81,58 +81,58 @@ ao_log(void) ao_storage_setup(); - ao_log_scan(); - - while (!ao_log_running) - ao_sleep(&ao_log_running); - - log.type = AO_LOG_FLIGHT; - log.tick = ao_time(); - log.u.flight.idle_pressure = ao_idle_pressure; - log.u.flight.idle_thrust = ao_idle_thrust; - log.u.flight.flight = ao_flight_number; - ao_log_firetwo(&log); - - /* Write the whole contents of the ring to the log - * when starting up. - */ - ao_log_data_pos = ao_data_ring_next(ao_data_head); - ao_log_state = ao_flight_startup; - for (;;) { - /* Write samples to EEPROM */ - while (ao_log_data_pos != ao_data_head) { - log.tick = ao_data_ring[ao_log_data_pos].tick; - log.type = AO_LOG_SENSOR; - log.u.sensor.pressure = ao_data_ring[ao_log_data_pos].adc.pressure; - log.u.sensor.thrust = ao_data_ring[ao_log_data_pos].adc.thrust; -// for (i = 0; i < 4; i++) { -// log.u.sensor.thermistor[i] = ao_data_ring[ao_log_data_pos].sensor.thermistor[i]; -// } - ao_log_firetwo(&log); - ao_log_data_pos = ao_data_ring_next(ao_log_data_pos); - } - /* Write state change to EEPROM */ - if (ao_flight_state != ao_log_state) { - ao_log_state = ao_flight_state; - log.type = AO_LOG_STATE; - log.tick = ao_time(); - log.u.state.state = ao_log_state; - log.u.state.reason = 0; - ao_log_firetwo(&log); - - if (ao_log_state == ao_flight_landed) - ao_log_stop(); - } - - ao_log_flush(); - - /* Wait for a while */ - ao_delay(AO_MS_TO_TICKS(100)); - - /* Stop logging when told to */ + do { + ao_log_scan(); + while (!ao_log_running) ao_sleep(&ao_log_running); - } + + log.type = AO_LOG_FLIGHT; + log.tick = ao_time(); + log.u.flight.idle_pressure = ao_idle_pressure; + log.u.flight.idle_thrust = ao_idle_thrust; + log.u.flight.flight = ao_flight_number; + ao_log_firetwo(&log); + + /* Write the whole contents of the ring to the log + * when starting up. + */ + ao_log_data_pos = ao_data_ring_next(ao_data_head); + ao_log_state = ao_flight_startup; + for (;;) { + /* Write samples to EEPROM */ + while (ao_log_data_pos != ao_data_head) { + log.tick = ao_data_ring[ao_log_data_pos].tick; + log.type = AO_LOG_SENSOR; + log.u.sensor.pressure = ao_data_ring[ao_log_data_pos].adc.pressure; + log.u.sensor.thrust = ao_data_ring[ao_log_data_pos].adc.thrust; + // for (i = 0; i < 4; i++) { + // log.u.sensor.thermistor[i] = ao_data_ring[ao_log_data_pos].sensor.thermistor[i]; + // } + ao_log_firetwo(&log); + ao_log_data_pos = ao_data_ring_next(ao_log_data_pos); + } + /* Write state change to EEPROM */ + if (ao_flight_state != ao_log_state) { + ao_log_state = ao_flight_state; + log.type = AO_LOG_STATE; + log.tick = ao_time(); + log.u.state.state = ao_log_state; + log.u.state.reason = 0; + ao_log_firetwo(&log); + + if (ao_log_state == ao_flight_landed) + ao_log_stop(); + } + + ao_log_flush(); + + if (!ao_log_running) break; + + /* Wait for a while */ + ao_delay(AO_MS_TO_TICKS(100)); + } + } while (ao_log_running); } uint16_t -- cgit v1.2.3 From b6b58aa2fbae1e7782b5a0b700544efe319fe34e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sat, 22 Apr 2017 22:04:31 -0700 Subject: altos: Move old AO_LAUNCH defines to cc1111/ao_launch.h These were getting accidentally used by ao_pad.c Signed-off-by: Keith Packard --- src/cc1111/ao_launch.c | 1 + src/cc1111/ao_launch.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/kernel/ao.h | 27 --------------------------- 3 files changed, 45 insertions(+), 27 deletions(-) create mode 100644 src/cc1111/ao_launch.h (limited to 'src') diff --git a/src/cc1111/ao_launch.c b/src/cc1111/ao_launch.c index 4f0a0c14..76d6d13b 100644 --- a/src/cc1111/ao_launch.c +++ b/src/cc1111/ao_launch.c @@ -17,6 +17,7 @@ */ #include +#include #include __xdata uint16_t ao_launch_ignite; diff --git a/src/cc1111/ao_launch.h b/src/cc1111/ao_launch.h new file mode 100644 index 00000000..966b5cea --- /dev/null +++ b/src/cc1111/ao_launch.h @@ -0,0 +1,44 @@ +/* + * Copyright © 2017 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _AO_LAUNCH_H_ +#define _AO_LAUNCH_H_ +/* ao_launch.c */ + +struct ao_launch_command { + uint16_t tick; + uint16_t serial; + uint8_t cmd; + uint8_t channel; + uint16_t unused; +}; + +#define AO_LAUNCH_QUERY 1 + +struct ao_launch_query { + uint16_t tick; + uint16_t serial; + uint8_t channel; + uint8_t valid; + uint8_t arm_status; + uint8_t igniter_status; +}; + +#define AO_LAUNCH_ARM 2 +#define AO_LAUNCH_FIRE 3 + +void +ao_launch_init(void); + +#endif /* _AO_LAUNCH_H_ */ diff --git a/src/kernel/ao.h b/src/kernel/ao.h index 9ab7991b..e56fbb2e 100644 --- a/src/kernel/ao.h +++ b/src/kernel/ao.h @@ -856,33 +856,6 @@ struct ao_fifo { #include #endif -/* ao_launch.c */ - -struct ao_launch_command { - uint16_t tick; - uint16_t serial; - uint8_t cmd; - uint8_t channel; - uint16_t unused; -}; - -#define AO_LAUNCH_QUERY 1 - -struct ao_launch_query { - uint16_t tick; - uint16_t serial; - uint8_t channel; - uint8_t valid; - uint8_t arm_status; - uint8_t igniter_status; -}; - -#define AO_LAUNCH_ARM 2 -#define AO_LAUNCH_FIRE 3 - -void -ao_launch_init(void); - /* * ao_log_single.c */ -- cgit v1.2.3 From 8e5b4359050701513a807131564ae54f2e6b919b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 24 Apr 2017 16:40:46 -0700 Subject: altos/ao_pad.c: Use #if HAS_LOG instead of #ifdef HAS_LOG TeleFire v0.1 defines HAS_LOG to 0. Signed-off-by: Keith Packard --- src/drivers/ao_pad.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/drivers/ao_pad.c b/src/drivers/ao_pad.c index c18cdd8d..16b4ae60 100644 --- a/src/drivers/ao_pad.c +++ b/src/drivers/ao_pad.c @@ -377,7 +377,7 @@ ao_pad(void) PRINTD ("not armed\n"); break; } -#ifdef HAS_LOG +#if HAS_LOG if (!ao_log_running) ao_log_start(); #endif if ((uint16_t) (ao_time() - ao_pad_arm_time) > AO_SEC_TO_TICKS(20)) { @@ -391,7 +391,7 @@ ao_pad(void) ao_wakeup(&ao_pad_ignite); break; case AO_PAD_ENDSTATIC: -#ifdef HAS_LOG +#if HAS_LOG ao_log_stop(); #endif break; -- cgit v1.2.3