Compare commits

..

No commits in common. "65d615407c670a32ace121e63542ad878eff8b2c" and "f0945b922730615f97be1784e60ffb3f0a9d0709" have entirely different histories.

7 changed files with 128 additions and 136 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

168
src/cmd.c
View file

@ -11,7 +11,14 @@
#include "pipe.h" #include "pipe.h"
uint8_t cmd_buffer[16]; uint8_t cmd_buffer[16];
uint8_t flash_buffer_valid; uint8_t cmd_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
@ -62,11 +69,23 @@ 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 {
@ -113,122 +132,95 @@ 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 (cmd < 'A' || cmd > 'Z') if (*s =='`')
return; return;
send_char('#'); uint8_t r = 0x08|cmd;
send_char('`');
send_char(cmd); send_char(cmd);
uint8_t bflg = *s - '0'; uint8_t have_b = !(cmd & 0x20);
uint8_t *bptr = cmd_buffer; cmd |= 0x20;
if (bflg <= 5) { if (cmd > 'z')
bptr = flash_buffer + 16*bflg; goto error;
bflg = 1<<bflg; if (have_b) {
s++; s = base85_fill_buffer(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;
} }
have_b = 1; cmd_buffer_valid |= 0x80;
} }
if (*s != '\n') s = skip_space(s);
goto error; uint8_t flag = *s++;
switch(cmd) { switch(cmd) {
case 'A': case 'a':
r = adc_current; r = adc_current;
if (r >= N_ADC) { if (r >= N_ADC) {
if (cmd_flag('<')) if (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);
if (cmd_flag('!')) flag = *s++;
}
if (flag == '+')
start_adc(); start_adc();
} }
break; break;
case 'B': case 'b':
if (have_b && bflg) { r = cmd_buffer_valid;
if (cmd_flag('|')) if (have_b) {
flash_buffer_valid |= bflg; flag -= '0';
memcpy(bptr, cmd_buffer, 16); if (flag < 5 && flag==cmd_buffer_valid) {
memcpy(flash_buffer+16*flag, cmd_buffer, 16);
r = cmd_buffer_valid |= 1<<flag;
flag = *++s;
} }
if (cmd_flag('%')) {
if (cmd_flag('!'))
memset(bch_parity, 0, 16);
bch4369_str(bptr, 16);
} }
if (cmd_flag('<')) { if (flag == '%') {
if (cmd_flag('|')) if (*s=='<')
flash_buffer_valid &=~ bflg; base85_send_buffer(bch_parity);
base85_send_buffer(bptr);
}
r = flash_buffer_valid;
break;
case 'F':
if (have_b) if (have_b)
bch4369_feed_buffer(*++s);
}
else if (flag == '<') {
flag = *s - '0';
uint8_t *b;
if (flag < 5)
b = flash_buffer + 16*flag;
else {
b = cmd_buffer;
}
base85_send_buffer(b);
}
break;
case 'f':
if (have_b) {
r = flash_submit_command(cmd_buffer); r = flash_submit_command(cmd_buffer);
cmd_buffer_valid &=~ 0x80;
}
else else
r = flash_poll(cmd_flag('!')); r = flash_poll(flag=='!');
break; break;
case 'P': case 'p':
if (have_b) if (have_b) {
r = pipe_config(cmd_buffer); r = pipe_config(cmd_buffer, flag);
cmd_buffer_valid &= ~0x80;
}
else else
r = pipe_poll(cmd_flag('!')); r = pipe_poll(flag=='!');
break; break;
case 'M': case 'm':
if (poke((void*)cmd_buffer, have_b, have_b && cmd_flag('!'))) if (poke((void*)cmd_buffer, have_b, have_b && 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,6 +264,12 @@ 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) {
@ -279,6 +285,7 @@ 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;
@ -304,12 +311,11 @@ 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()) {
@ -325,7 +331,6 @@ 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,6 +1,5 @@
#include "pipe.h" #include <pipe.h>
#include "flash.h"
struct pipe pipe; struct pipe pipe;
@ -12,15 +11,12 @@ struct pipe_config {
uint8_t flash_page; uint8_t flash_page;
}; };
uint8_t pipe_config(const uint8_t *) uint8_t pipe_config(const uint8_t *, uint8_t flag)
{ {
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 pipe_config(const uint8_t *, uint8_t flag);
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, naked)) __attribute__ ((noinline, noclone))
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 r31, %[STATUS] \n" " lds r30, %[STATUS] \n"
" sbrc r31, %[DRE] \n" " sbrc r30, %[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"
" ret \n" " sts uart_tx_r, r21 \n"
: :
: :
[TXC] "n" (USART_TXCIF_bp), [TXC] "n" (USART_TXCIF_bp),
@ -96,7 +96,8 @@ void tx()
ISR(USART0_DRE_vect, ISR_NAKED) ISR(USART0_DRE_vect, ISR_NAKED)
{ {
// This saves five instructions and two bytes stack (r0, r1). // Doing this naked is a bit dangerous,
// 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,7 +9,6 @@
.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
@ -18,16 +17,37 @@
// `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:
// non-global, non-C
// 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 // r18, r26, and 27 must be preseved in the hex functions
// , r20, r21, r24, must be preserved in `uart_busy()` and `put_char()' // , 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
@ -37,13 +57,11 @@ 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
@ -57,43 +75,24 @@ send_hex_nibble:
subi r24, '9'+1-'A' subi r24, '9'+1-'A'
send_char: send_char:
mov r22, r24 mov r22, r24
rjmp _send_char22 send_char22:
1: rcall put_char
brne 9f
rcall uart_busy rcall uart_busy
sleep sleep
_send_char22: rjmp 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:
__send_char22_str26: rcall send_char22
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
@ -104,7 +103,6 @@ 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