Compare commits

...

2 commits

Author SHA1 Message Date
Stephan I. Böttcher
65d615407c parse_command refactor 2026-01-06 13:58:50 +01:00
Stephan I. Böttcher
bd0238bb2d fixes and cleanups 2026-01-06 00:11:01 +01:00
7 changed files with 136 additions and 128 deletions

View file

@ -89,7 +89,7 @@ base85_encode:
.global mul85 .global mul85
mul85: mul85:
# endif # endif
;; TODO for SPACE: inline this
_mul85: _mul85:
ldi r21, 85 ldi r21, 85
mul r25, r21 mul r25, r21

166
src/cmd.c
View file

@ -11,14 +11,7 @@
#include "pipe.h" #include "pipe.h"
uint8_t cmd_buffer[16]; uint8_t cmd_buffer[16];
uint8_t cmd_buffer_valid; uint8_t flash_buffer_valid;
static __attribute__((noinline))
const uint8_t *skip_space(const uint8_t *s) {
if (*s == ' ')
s++;
return s;
}
uint8_t base85_str[6]; uint8_t base85_str[6];
#if 0 #if 0
@ -69,23 +62,11 @@ void base85_send_buffer(const uint8_t *buf)
static inline static inline
const uint8_t *base85_fill_buffer(const uint8_t *s) { const uint8_t *base85_fill_buffer(const uint8_t *s) {
base85_error = 0; base85_error = 0;
s = skip_space(s);
for (int i=0; !base85_error && i<FB_SIZE; i+=4) for (int i=0; !base85_error && i<FB_SIZE; i+=4)
s = base85_decode(s, (uint32_t *)(cmd_buffer + i)); s = base85_decode(s, (uint32_t *)(cmd_buffer + i));
s = skip_space(s);
return s; return s;
} }
static inline
void bch4369_feed_buffer(uint8_t flag)
{
if (flag=='0') {
memset(bch_parity, 0, 16);
}
bch4369_str(cmd_buffer,16);
}
uint8_t * poke_addr; uint8_t * poke_addr;
uint8_t peek_size; uint8_t peek_size;
struct peak_poke { struct peak_poke {
@ -132,95 +113,122 @@ uint8_t poke(struct peak_poke *p, uint8_t hp, uint8_t poke)
return s && !poke; return s && !poke;
} }
const uint8_t *cmd_flags;
#if 0
static __attribute__((noinline))
uint8_t cmd_flag(uint8_t f)
{
if (*cmd_flags == f) {
cmd_flags++;
send_char(f);
return f;
}
return 0;
}
#else
static __attribute__((noinline, naked))
uint8_t cmd_flag(uint8_t f)
{
// _send_char22 does not gobble r24.
__asm__(
""
"lds r30, cmd_flags" "\n\t"
"lds r31, cmd_flags+1" "\n\t"
"ld r22, Z+" "\n\t"
"cp r22, r24" "\n\t"
"mov r24, r1" "\n\t"
"brne 9f" "\n\t"
"mov r24, r22" "\n\t"
"sts cmd_flags, r30" "\n\t"
"sts cmd_flags+1, r31" "\n\t"
"rcall _send_char22" "\n"
"9:" "\n\t"
"ret" "\n"
);
}
#endif
void parse_command(const uint8_t *s, uint8_t n) void parse_command(const uint8_t *s, uint8_t n)
{ {
// ^[A-Z][!-@]+( [!-u]{20}])?$
// cmd flags base85
uint8_t r = 0;
uint8_t cmd = *s++; uint8_t cmd = *s++;
if (*s =='`') if (cmd < 'A' || cmd > 'Z')
return; return;
uint8_t r = 0x08|cmd; send_char('#');
send_char('`');
send_char(cmd); send_char(cmd);
uint8_t have_b = !(cmd & 0x20); uint8_t bflg = *s - '0';
cmd |= 0x20; uint8_t *bptr = cmd_buffer;
if (cmd > 'z') if (bflg <= 5) {
goto error; bptr = flash_buffer + 16*bflg;
if (have_b) { bflg = 1<<bflg;
s = base85_fill_buffer(s); s++;
}
else
bflg = 0;
cmd_flags = s;
while (*s > ' ' && *s < 'A')
s++;
uint8_t have_b = 0;
if (*s==' ') {
s = base85_fill_buffer(s+1);
if (base85_error) { if (base85_error) {
r = base85_error; r = base85_error;
goto error; goto error;
} }
cmd_buffer_valid |= 0x80; have_b = 1;
} }
s = skip_space(s); if (*s != '\n')
uint8_t flag = *s++; goto error;
switch(cmd) { switch(cmd) {
case 'a': case 'A':
r = adc_current; r = adc_current;
if (r >= N_ADC) { if (r >= N_ADC) {
if (flag=='=') { if (cmd_flag('<'))
memcpy(cmd_buffer, adc_readings, 16);
cmd_buffer_valid |= 0x40;
flag = *s++;
}
if (flag == '<') {
base85_send_buffer((void*)adc_readings); base85_send_buffer((void*)adc_readings);
flag = *s++; if (cmd_flag('!'))
}
if (flag == '+')
start_adc(); start_adc();
} }
break; break;
case 'b': case 'B':
r = cmd_buffer_valid; if (have_b && bflg) {
if (have_b) { if (cmd_flag('|'))
flag -= '0'; flash_buffer_valid |= bflg;
if (flag < 5 && flag==cmd_buffer_valid) { memcpy(bptr, cmd_buffer, 16);
memcpy(flash_buffer+16*flag, cmd_buffer, 16);
r = cmd_buffer_valid |= 1<<flag;
flag = *++s;
}
} }
if (flag == '%') { if (cmd_flag('%')) {
if (*s=='<') if (cmd_flag('!'))
base85_send_buffer(bch_parity); memset(bch_parity, 0, 16);
if (have_b) bch4369_str(bptr, 16);
bch4369_feed_buffer(*++s);
} }
else if (flag == '<') { if (cmd_flag('<')) {
flag = *s - '0'; if (cmd_flag('|'))
uint8_t *b; flash_buffer_valid &=~ bflg;
if (flag < 5) base85_send_buffer(bptr);
b = flash_buffer + 16*flag;
else {
b = cmd_buffer;
}
base85_send_buffer(b);
} }
r = flash_buffer_valid;
break; break;
case 'f': case 'F':
if (have_b) { if (have_b)
r = flash_submit_command(cmd_buffer); r = flash_submit_command(cmd_buffer);
cmd_buffer_valid &=~ 0x80;
}
else else
r = flash_poll(flag=='!'); r = flash_poll(cmd_flag('!'));
break; break;
case 'p': case 'P':
if (have_b) { if (have_b)
r = pipe_config(cmd_buffer, flag); r = pipe_config(cmd_buffer);
cmd_buffer_valid &= ~0x80;
}
else else
r = pipe_poll(flag=='!'); r = pipe_poll(cmd_flag('!'));
break; break;
case 'm': case 'M':
if (poke((void*)cmd_buffer, have_b, have_b && flag=='!')) if (poke((void*)cmd_buffer, have_b, have_b && cmd_flag('!')))
base85_send_buffer(cmd_buffer); base85_send_buffer(cmd_buffer);
break;
default: default:
error: error:
send_char('?'); send_char('?');
} }
send_hex_byte_eol(r); send_hex_byte_eol(r);
} }

View file

@ -264,12 +264,6 @@ void bch_flash_init()
uint8_t flash_poll(uint8_t rr) uint8_t flash_poll(uint8_t rr)
{ {
uint8_t r = fs.status; uint8_t r = fs.status;
if (spi_busy_p()) {
if (rr)
goto collision;
fs.status = r | FS_Busy;
return r;
}
if ((r & FS_Error) == FS_Error) if ((r & FS_Error) == FS_Error)
return r; return r;
if (r & FS_StBsy) { if (r & FS_StBsy) {
@ -285,7 +279,6 @@ uint8_t flash_poll(uint8_t rr)
if (!(r & FS_Busy)) if (!(r & FS_Busy))
goto ready; goto ready;
if (rr) { if (rr) {
collision:
r |= FS_Error; r |= FS_Error;
fs.status = r; fs.status = r;
return r; return r;
@ -311,11 +304,12 @@ uint8_t flash_poll(uint8_t rr)
} }
ready: ready:
r &= ~(FS_Busy | FS_StBsy);
if (rr) if (rr)
r |= FS_Ack; r |= FS_Ack;
// clear the Bsy bits
r &= ~(FS_Busy | FS_StBsy);
fs.status = r; fs.status = r;
if (spi_busy_p())
return r;
if (r & FS_Dir == FS_Write && fs.block == 8) if (r & FS_Dir == FS_Write && fs.block == 8)
flash_burn_page(); flash_burn_page();
else if (!flash_stream_done()) { else if (!flash_stream_done()) {
@ -331,6 +325,7 @@ ready:
} }
else if (r & FS_Dir == FS_Erase) else if (r & FS_Dir == FS_Erase)
flash_erase_next_page(); flash_erase_next_page();
fs.status &=~ FS_Ack;
} }
return fs.status; return fs.status;
} }

View file

@ -1,5 +1,6 @@
#include <pipe.h> #include "pipe.h"
#include "flash.h"
struct pipe pipe; struct pipe pipe;
@ -11,12 +12,15 @@ struct pipe_config {
uint8_t flash_page; uint8_t flash_page;
}; };
uint8_t pipe_config(const uint8_t *, uint8_t flag) uint8_t pipe_config(const uint8_t *)
{ {
return 0; return 0;
} }
uint8_t pipe_poll(uint8_t flag) uint8_t pipe_poll(uint8_t flag)
{ {
uint8_t r = pipe.status;
if (spi_busy_p() || flash_poll(0) & FS_Busy)
return r;
return 0; return 0;
} }

View file

@ -1,7 +1,7 @@
#include <stdint.h> #include <stdint.h>
uint8_t pipe_config(const uint8_t *, uint8_t flag); uint8_t pipe_config(const uint8_t *);
uint8_t pipe_poll(uint8_t flag); uint8_t pipe_poll(uint8_t flag);
enum pipe_ports { enum pipe_ports {

View file

@ -51,7 +51,7 @@ ISR(USART0_DRE_vect)
#else #else
__attribute__ ((noinline, noclone)) __attribute__ ((noinline, naked))
void tx() void tx()
{ {
// This uses only three registers, to save stack in the ISR. // This uses only three registers, to save stack in the ISR.
@ -76,13 +76,13 @@ void tx()
" lds r31, uart_tx_w \n" " lds r31, uart_tx_w \n"
" cp r30, r31 \n" " cp r30, r31 \n"
" breq 3f \n" " breq 3f \n"
" lds r30, %[STATUS] \n" " lds r31, %[STATUS] \n"
" sbrc r30, %[DRE] \n" " sbrc r31, %[DRE] \n"
" rjmp 1b \n" " rjmp 1b \n"
" ori r25, 1<<%[DRE] \n" " ori r25, 1<<%[DRE] \n"
"3: \n" "3: \n"
" sts %[CTRLA], r25 \n" " sts %[CTRLA], r25 \n"
" sts uart_tx_r, r21 \n" " ret \n"
: :
: :
[TXC] "n" (USART_TXCIF_bp), [TXC] "n" (USART_TXCIF_bp),
@ -96,8 +96,7 @@ void tx()
ISR(USART0_DRE_vect, ISR_NAKED) ISR(USART0_DRE_vect, ISR_NAKED)
{ {
// Doing this naked is a bit dangerous, // This saves five instructions and two bytes stack (r0, r1).
// but saves five instructions and two bytes stack (r0, r1).
// OTOH, the C implementation of tx() is not bad either, // OTOH, the C implementation of tx() is not bad either,
// if we are doing this asm, then we do it agressively. // if we are doing this asm, then we do it agressively.
__asm__("\n" __asm__("\n"

View file

@ -9,6 +9,7 @@
.global send_hex_byte .global send_hex_byte
.global send_hex_byte_eol .global send_hex_byte_eol
.global send_char .global send_char
.global _send_char22
.global send_str .global send_str
.global _send_str26 .global _send_str26
.global uart_busy .global uart_busy
@ -17,37 +18,16 @@
// `tx()` and `put_char()` do not gobble r18, r20, r21, r22, r24, r26, and r27. // `tx()` and `put_char()` do not gobble r18, r20, r21, r22, r24, r26, and r27.
put_char: // r18, r26, and 27 must be preseved in the hex functions
// non-global, non-C // , r20, r21, r24, must be preserved in `uart_busy()` and `put_char()'
// arg: char r22
lds r23, uart_tx_r
lds r30, uart_tx_w
ldi r19, 1
add r19, r30
eor r23, r19
andi r30, 0x1f // uart_tx_m
ldi r31, 0
subi r30, lo8(-(uart_tx))
sbci r31, hi8(-(uart_tx))
andi r23, 0x1f // uart_tx_m
breq 1f
st Z, r22
sts uart_tx_w, r19
1:
// r22 preserved
// r23 full when zero
ret
// r18, r26, and 27 must be preseved in the hex functions
// , r20, r21, r24, must be preserved in `uart_busy()` and `put_char()'
send_hex_byte_eol: send_hex_byte_eol:
ldi r22, ' ' ldi r22, ' '
rcall send_char22 rcall _send_char22
rcall send_hex_byte rcall send_hex_byte
send_eol: send_eol:
ldi r22, '\n' ldi r22, '\n'
rcall send_char22 rcall _send_char22
uart_busy: uart_busy:
cli cli
rcall tx ; gobbles r25, r30, and r31 rcall tx ; gobbles r25, r30, and r31
@ -57,11 +37,13 @@ uart_busy:
9: 9:
ret ret
#ifdef HEX_WORD
send_hex_word: send_hex_word:
mov r20, r24 mov r20, r24
mov r24, r25 mov r24, r25
rcall send_hex_byte rcall send_hex_byte
mov r24, r20 mov r24, r20
#endif
send_hex_byte: send_hex_byte:
mov r21, r24 mov r21, r24
swap r24 swap r24
@ -75,24 +57,43 @@ send_hex_nibble:
subi r24, '9'+1-'A' subi r24, '9'+1-'A'
send_char: send_char:
mov r22, r24 mov r22, r24
send_char22: rjmp _send_char22
rcall put_char 1:
brne 9f
rcall uart_busy rcall uart_busy
sleep sleep
rjmp send_char22 _send_char22:
// non-global, non-C
// arg: char r22
lds r23, uart_tx_r
lds r30, uart_tx_w
ldi r19, 1
add r19, r30
sub r23, r19
andi r30, 0x1f // uart_tx_m
ldi r31, 0
subi r30, lo8(-(uart_tx))
sbci r31, hi8(-(uart_tx))
subi r23, 0xe0
brcs 1b
st Z, r22
sts uart_tx_w, r19
9:
ret
send_str: send_str:
movw r26, r24 movw r26, r24
rjmp _send_str26 rjmp _send_str26
1: 1:
rcall send_char22 __send_char22_str26:
rcall _send_char22
_send_str26: _send_str26:
ld r22, X+ ld r22, X+
tst r22 tst r22
brne 1b brne 1b
9:
ret ret
#ifdef SEND_HEX
send_hex: send_hex:
movw r26, r24 movw r26, r24
mov r18, r22 mov r18, r22
@ -103,6 +104,7 @@ send_hex:
brcc 1b brcc 1b
9: 9:
ret ret
#endif
command: command:
;; when any frame errors occured, dismiss the buffer ;; when any frame errors occured, dismiss the buffer