Compare commits
14 commits
d495bc2db1
...
c348b6a271
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c348b6a271 | ||
|
|
69b27506a4 | ||
|
|
0bda97fd39 | ||
|
|
6bb065d3c5 | ||
|
|
d684d51554 | ||
|
|
d64e1fd749 | ||
|
|
db9709f7a8 | ||
|
|
6db31a6c7d | ||
|
|
025417be68 | ||
|
|
a9f83f8628 | ||
|
|
3a0e72eb52 | ||
|
|
b6cdc1991f | ||
|
|
f7c1e27d48 | ||
|
|
b1356355db |
10 changed files with 285 additions and 134 deletions
23
src/cmd.c
23
src/cmd.c
|
|
@ -206,11 +206,11 @@ void parse_command(const uint8_t *s, uint8_t n)
|
||||||
pipe.valid = 0;
|
pipe.valid = 0;
|
||||||
r = pipe.valid;
|
r = pipe.valid;
|
||||||
if (have_b) {
|
if (have_b) {
|
||||||
if (cmd_flag('!') || ~r & bflg) {
|
if (bflg && cmd_flag('!') || ~r & bflg) {
|
||||||
memcpy(bptr, cmd_buffer, 16);
|
memcpy(bptr, cmd_buffer, 16);
|
||||||
r = pipe.valid |= bflg;
|
pipe.valid = r |= bflg;
|
||||||
}
|
}
|
||||||
else
|
else if (bflg)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (cmd_flag('%')) {
|
if (cmd_flag('%')) {
|
||||||
|
|
@ -220,14 +220,15 @@ void parse_command(const uint8_t *s, uint8_t n)
|
||||||
if (cmd_flag('!')) {
|
if (cmd_flag('!')) {
|
||||||
bch4369_fini();
|
bch4369_fini();
|
||||||
memcpy(flash_buffer+64, bch_parity, 16);
|
memcpy(flash_buffer+64, bch_parity, 16);
|
||||||
r = pipe.valid |= 0x10;
|
pipe.valid = r |= 0x10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cmd_flag('<')) {
|
if (cmd_flag('<')) {
|
||||||
if (cmd_flag('!')) goto send_buffer;
|
if (cmd_flag('!')) goto send_buffer;
|
||||||
if (~r & bflg)
|
if (~r & bflg)
|
||||||
goto error;
|
goto error;
|
||||||
pipe.valid &=~ bflg;
|
pipe.valid = r &=~ bflg;
|
||||||
|
r |= pipe.status << 4;
|
||||||
goto send_buffer;
|
goto send_buffer;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -240,17 +241,23 @@ void parse_command(const uint8_t *s, uint8_t n)
|
||||||
r = flash_submit_command(cmd_buffer);
|
r = flash_submit_command(cmd_buffer);
|
||||||
else
|
else
|
||||||
r = spi_busy_p();
|
r = spi_busy_p();
|
||||||
if (cmd_flag('@'))
|
if (cmd_flag('!'))
|
||||||
spi_poll();
|
spi_poll();
|
||||||
if (cmd_flag('<'))
|
if (cmd_flag('<'))
|
||||||
goto send_buffer;
|
goto send_buffer;
|
||||||
break;
|
break;
|
||||||
case 'P':
|
case 'P':
|
||||||
if (cmd_flag('!'))
|
if (cmd_flag('@'))
|
||||||
pipe.dest = 0;
|
pipe.dest = 0;
|
||||||
if (have_b)
|
if (have_b)
|
||||||
pipe_config((void*)cmd_buffer, (void*)bptr);
|
pipe_config((void*)cmd_buffer, (void*)bptr);
|
||||||
r = pipe_poll();
|
if (cmd_flag('.'))
|
||||||
|
flash_poll(0);
|
||||||
|
else if (cmd_flag(','))
|
||||||
|
flash_poll(1);
|
||||||
|
if (cmd_flag('!'))
|
||||||
|
pipe_poll();
|
||||||
|
r = pipe.status;
|
||||||
break;
|
break;
|
||||||
#ifdef HAVE_FPGA
|
#ifdef HAVE_FPGA
|
||||||
case 'O':
|
case 'O':
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ enum magic_flags {
|
||||||
MAGIC = 0xC5,
|
MAGIC = 0xC5,
|
||||||
VERSION = 0x00,
|
VERSION = 0x00,
|
||||||
#endif
|
#endif
|
||||||
|
hold_pipe = 0x01,
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const struct config config;
|
extern const struct config config;
|
||||||
|
|
@ -158,6 +159,7 @@ void apply_config()
|
||||||
extern struct magic {
|
extern struct magic {
|
||||||
uint8_t magic;
|
uint8_t magic;
|
||||||
uint8_t reset_source;
|
uint8_t reset_source;
|
||||||
|
uint8_t flags;
|
||||||
} magic;
|
} magic;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
|
||||||
220
src/dose.py
220
src/dose.py
|
|
@ -66,6 +66,16 @@ mmap = memmap(map_fn)
|
||||||
|
|
||||||
class dose_cmd(uart.uart):
|
class dose_cmd(uart.uart):
|
||||||
|
|
||||||
|
def parse_line(self, l):
|
||||||
|
self.responses.append(l)
|
||||||
|
v = self._verbose
|
||||||
|
if v>=4 or v and (l[:1]!=b'#' or b'?' in l.split()[0]):
|
||||||
|
try:
|
||||||
|
s = l.decode()
|
||||||
|
print(f"{self.portname}<- {s}", file=sys.stderr)
|
||||||
|
except:
|
||||||
|
print(f"{self.portname}<- {repr(l)}", file=sys.stderr)
|
||||||
|
|
||||||
def cmd(self, c, d=None, timeout=0.2):
|
def cmd(self, c, d=None, timeout=0.2):
|
||||||
if not isinstance(c, bytes):
|
if not isinstance(c, bytes):
|
||||||
c = c.encode()
|
c = c.encode()
|
||||||
|
|
@ -83,7 +93,7 @@ class dose_cmd(uart.uart):
|
||||||
e = int(r[-1], 16)
|
e = int(r[-1], 16)
|
||||||
if len(r)==3:
|
if len(r)==3:
|
||||||
d = base85_decode(r[1])
|
d = base85_decode(r[1])
|
||||||
if self._verbose:
|
if self._verbose >= 3:
|
||||||
print(f"{r[0]}[{r[2]}] {"".join([f"{b:02x}" for b in d])}", file=sys.stderr)
|
print(f"{r[0]}[{r[2]}] {"".join([f"{b:02x}" for b in d])}", file=sys.stderr)
|
||||||
self.last_cmd = c[0:1]
|
self.last_cmd = c[0:1]
|
||||||
return r[0], e, d
|
return r[0], e, d
|
||||||
|
|
@ -91,26 +101,32 @@ class dose_cmd(uart.uart):
|
||||||
def poke(self, a, d, s=None, ccp=0):
|
def poke(self, a, d, s=None, ccp=0):
|
||||||
return self.peek(a, s=s, d=d, ccp=ccp)
|
return self.peek(a, s=s, d=d, ccp=ccp)
|
||||||
|
|
||||||
def peek(self, a=None, s=None, d=None, ccp=0):
|
def peek(self, a=None, s=None, d=None, ccp=0, o=0):
|
||||||
name = None
|
name = None
|
||||||
if a in SFR:
|
|
||||||
name = a
|
|
||||||
a, ss = SFR[a]
|
|
||||||
if s is None:
|
|
||||||
s = ss
|
|
||||||
if a in mmap:
|
|
||||||
a, ss = mmap[a]
|
|
||||||
if ss and s is None:
|
|
||||||
s = ss
|
|
||||||
if isinstance(a, str):
|
if isinstance(a, str):
|
||||||
print(f"PEEK: unknown addr {a}", file=sys.stderr)
|
aa = a.split('+',1)
|
||||||
for k in mmap.keys():
|
if aa[1:]:
|
||||||
if a in k:
|
o += int(aa[1], 0)
|
||||||
print(f"PEEK: in RAM we have {k}", file=sys.stderr)
|
aa = aa[0]
|
||||||
for k in SFR.keys():
|
if aa in SFR:
|
||||||
if a in k:
|
name = aa
|
||||||
print(f"PEEK: IO SFR we have {k}", file=sys.stderr)
|
a, ss = SFR[aa]
|
||||||
raise ValueError(a)
|
if s is None:
|
||||||
|
s = ss
|
||||||
|
elif aa in mmap:
|
||||||
|
a, ss = mmap[aa]
|
||||||
|
if ss and s is None:
|
||||||
|
s = ss
|
||||||
|
else:
|
||||||
|
print(f"PEEK: unknown addr {a}", file=sys.stderr)
|
||||||
|
for k in mmap.keys():
|
||||||
|
if a in k:
|
||||||
|
print(f"PEEK: in RAM we have {k}", file=sys.stderr)
|
||||||
|
for k in SFR.keys():
|
||||||
|
if a in k:
|
||||||
|
print(f"PEEK: IO SFR we have {k}", file=sys.stderr)
|
||||||
|
raise ValueError(a)
|
||||||
|
a += o
|
||||||
FF = {1: "B", 2: "H", 4:"I"}
|
FF = {1: "B", 2: "H", 4:"I"}
|
||||||
if a is None:
|
if a is None:
|
||||||
cc, nn, dd = self.cmd(b"M=")
|
cc, nn, dd = self.cmd(b"M=")
|
||||||
|
|
@ -223,7 +239,10 @@ class dose_cmd(uart.uart):
|
||||||
def flash(self, op=None, resp=False, poll=False, **aa):
|
def flash(self, op=None, resp=False, poll=False, **aa):
|
||||||
c = "F"
|
c = "F"
|
||||||
if poll:
|
if poll:
|
||||||
c = "F@"
|
if poll in ".,!":
|
||||||
|
c = "F"+poll
|
||||||
|
else:
|
||||||
|
c = "F!"
|
||||||
if resp:
|
if resp:
|
||||||
c += "<"
|
c += "<"
|
||||||
if op is None:
|
if op is None:
|
||||||
|
|
@ -278,10 +297,8 @@ class dose_cmd(uart.uart):
|
||||||
if min(d) == 255:
|
if min(d) == 255:
|
||||||
print(f"FLASH: page is erased")
|
print(f"FLASH: page is erased")
|
||||||
elif bch.check_page(d):
|
elif bch.check_page(d):
|
||||||
if not bch.galois:
|
d = self.fix_page(d)
|
||||||
raise bch.BCHError("galois module not loaded for Parity Error correction")
|
return d
|
||||||
d = bch.fix_page(d)
|
|
||||||
return d[:512]
|
|
||||||
|
|
||||||
def read_flash(self, page):
|
def read_flash(self, page):
|
||||||
print(f"FLASH: reading from {page=}")
|
print(f"FLASH: reading from {page=}")
|
||||||
|
|
@ -355,6 +372,17 @@ class dose_cmd(uart.uart):
|
||||||
self.flash(op, size=s, what=what, byte=i)
|
self.flash(op, size=s, what=what, byte=i)
|
||||||
self.wait_for_spi()
|
self.wait_for_spi()
|
||||||
|
|
||||||
|
def make_parity(self, page):
|
||||||
|
for i in range(32):
|
||||||
|
if i==0:
|
||||||
|
c = "B4!%@"
|
||||||
|
elif i!=31:
|
||||||
|
c = "B4!%"
|
||||||
|
else:
|
||||||
|
c = "B4!%!"
|
||||||
|
self.cmd(c, page[16*i:16*(i+1)])
|
||||||
|
return self.cmd("B4<!")
|
||||||
|
|
||||||
def power(self, on=None):
|
def power(self, on=None):
|
||||||
if on==True:
|
if on==True:
|
||||||
c = 'O1'
|
c = 'O1'
|
||||||
|
|
@ -372,7 +400,6 @@ class dose_cmd(uart.uart):
|
||||||
return self.cmd("C@")
|
return self.cmd("C@")
|
||||||
|
|
||||||
FPGA_FLGS = {
|
FPGA_FLGS = {
|
||||||
"ABORT": 0x01,
|
|
||||||
"DEAD": 0x10,
|
"DEAD": 0x10,
|
||||||
"BUSY": 0x20,
|
"BUSY": 0x20,
|
||||||
"SUBMITTED": 0x40,
|
"SUBMITTED": 0x40,
|
||||||
|
|
@ -396,7 +423,7 @@ class dose_cmd(uart.uart):
|
||||||
c = bytes((n, z)) + c + bytes(14)
|
c = bytes((n, z)) + c + bytes(14)
|
||||||
r, e, d = self.cmd("C", c[:16])
|
r, e, d = self.cmd("C", c[:16])
|
||||||
s = int2flags(self.FPGA_FLGS, d[0])
|
s = int2flags(self.FPGA_FLGS, d[0])
|
||||||
if self._verbose:
|
if self._verbose >= 2:
|
||||||
print(f"FPGA cmd status {s!r}", file=sys.stderr)
|
print(f"FPGA cmd status {s!r}", file=sys.stderr)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
@ -462,7 +489,7 @@ class dose_cmd(uart.uart):
|
||||||
w.extend([0x8001]*(r-1))
|
w.extend([0x8001]*(r-1))
|
||||||
w.append(0)
|
w.append(0)
|
||||||
d = struct.pack(f">{len(w)}H", *w)
|
d = struct.pack(f">{len(w)}H", *w)
|
||||||
if self._verbose:
|
if self._verbose >= 2:
|
||||||
if mes:
|
if mes:
|
||||||
mes = f"[{mes}]"
|
mes = f"[{mes}]"
|
||||||
else:
|
else:
|
||||||
|
|
@ -470,13 +497,13 @@ class dose_cmd(uart.uart):
|
||||||
print(f"icmd{mes} → {[f"{ww:04x}" for ww in w]}")
|
print(f"icmd{mes} → {[f"{ww:04x}" for ww in w]}")
|
||||||
d = self.fpga_cmd(d)
|
d = self.fpga_cmd(d)
|
||||||
r = struct.unpack(f">{len(w)+1}H", d[:2*len(w)+2])
|
r = struct.unpack(f">{len(w)+1}H", d[:2*len(w)+2])
|
||||||
if self._verbose:
|
if self._verbose >= 2:
|
||||||
print(f" {mes} ← {[f"{rr:04x}" for rr in r]}", file=sys.stderr)
|
print(f" {mes} ← {[f"{rr:04x}" for rr in r]}", file=sys.stderr)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def acmd(self, c, v=None, task=None, verb=True):
|
def acmd(self, c, v=None, task=None, verb=True):
|
||||||
_v = self._verbose
|
_v = self._verbose
|
||||||
self._verbose = _v
|
self._verbose = verb+1
|
||||||
r = self.icmd(c, v, mes=task)[-1]
|
r = self.icmd(c, v, mes=task)[-1]
|
||||||
self._verbose = _v
|
self._verbose = _v
|
||||||
return r
|
return r
|
||||||
|
|
@ -500,7 +527,7 @@ class dose_cmd(uart.uart):
|
||||||
nnn -= nn
|
nnn -= nn
|
||||||
d += dd[2:]
|
d += dd[2:]
|
||||||
r = struct.unpack(f">{len(d)//2}H", d)[:n]
|
r = struct.unpack(f">{len(d)//2}H", d)[:n]
|
||||||
if self._verbose:
|
if self._verbose >= 2:
|
||||||
print(f"FIFO[{fifo}] ← {[f"{rr:04x}" for rr in r]}", file=sys.stderr)
|
print(f"FIFO[{fifo}] ← {[f"{rr:04x}" for rr in r]}", file=sys.stderr)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
@ -522,9 +549,140 @@ class dose_cmd(uart.uart):
|
||||||
else:
|
else:
|
||||||
self.icmd("MCONF_CLR", what)
|
self.icmd("MCONF_CLR", what)
|
||||||
|
|
||||||
|
PIPE = {
|
||||||
|
"CMD" : 1,
|
||||||
|
"ADC" : 2,
|
||||||
|
"FLASH" : 4,
|
||||||
|
"FPGA" : 8,
|
||||||
|
"CONFIG" : 0x208,
|
||||||
|
"FPGA_CMD" : 0x408,
|
||||||
|
}
|
||||||
|
|
||||||
|
def pipe(self, source=None, dest=None,
|
||||||
|
fpga_cmd=4, psize=64, n=0,
|
||||||
|
page=0, npages=0,
|
||||||
|
poll=True, stop=False):
|
||||||
|
astatus = flags2int(self.PIPE, dest)
|
||||||
|
astatus |= flags2int(self.PIPE, source)
|
||||||
|
astatus >>= 8
|
||||||
|
dest = flags2int(self.PIPE, dest) & 0xff
|
||||||
|
source = flags2int(self.PIPE, source) & 0xff
|
||||||
|
flash = 0x80 # FS_528
|
||||||
|
status = 0x80 # PS_OUT
|
||||||
|
c = 'P'
|
||||||
|
if astatus & self.PIPE["FPGA_CMD"]:
|
||||||
|
if not isinstance(fpga_cmd, int):
|
||||||
|
self.cmd("B4!", fpga_cmd)
|
||||||
|
fpga_cmd = 4
|
||||||
|
c = 'P{fpga_cmd}'
|
||||||
|
if stop:
|
||||||
|
c += '@'
|
||||||
|
if poll:
|
||||||
|
c += '!'
|
||||||
|
|
||||||
|
if source & self.PIPE["FLASH"]:
|
||||||
|
source = self.PIPE["FLASH"]
|
||||||
|
flash |= 4
|
||||||
|
status |= 0x30 # PS_528 | PS_BCH
|
||||||
|
dest &=~ self.PIPE["FLASH"]
|
||||||
|
if dest & self.PIPE["FPGA"] and not n:
|
||||||
|
n = 512/64 * npages
|
||||||
|
if dest & self.PIPE["FLASH"]:
|
||||||
|
flash |= 8
|
||||||
|
status |= 0x30 # PS_528 | PS_BCH
|
||||||
|
if source == self.PIPE["FPGA"] and not n:
|
||||||
|
n = (512*npages+psize-1) // psize
|
||||||
|
|
||||||
|
d = struct.pack("<6BH3B2HB",
|
||||||
|
source, dest, status, 0, 0,
|
||||||
|
astatus, n, psize, 0, 0,
|
||||||
|
page, npages-1, flash)
|
||||||
|
return self.cmd(c, d)
|
||||||
|
|
||||||
|
Sync = False
|
||||||
|
|
||||||
|
def read_pipe(self, n=0, file=None, timeout=2, parity=False):
|
||||||
|
if isinstance(file, str):
|
||||||
|
f = open(file, "ab")
|
||||||
|
else:
|
||||||
|
f = file
|
||||||
|
result = []
|
||||||
|
i = 0
|
||||||
|
page = []
|
||||||
|
t = time.time()
|
||||||
|
s = 1/256
|
||||||
|
while i < n:
|
||||||
|
cc, nn, dd = self.cmd("B")
|
||||||
|
if not parity or len(page) < 7:
|
||||||
|
bflg = 0x0f
|
||||||
|
else:
|
||||||
|
bflg = 0x1f
|
||||||
|
|
||||||
|
tt = time.time()
|
||||||
|
if ~nn & bflg:
|
||||||
|
if tt > t+timeout:
|
||||||
|
if self._verbose:
|
||||||
|
print("read_pipe timeout", file=sys.stderr)
|
||||||
|
break
|
||||||
|
time.sleep(s)
|
||||||
|
s *= 2
|
||||||
|
if s > 1:
|
||||||
|
s = 1
|
||||||
|
continue
|
||||||
|
t = tt
|
||||||
|
s = 1/256
|
||||||
|
|
||||||
|
if len(result) >= n:
|
||||||
|
break
|
||||||
|
|
||||||
|
if nn & 0x10:
|
||||||
|
p = self.cmd("B4<")[2]
|
||||||
|
else:
|
||||||
|
p = None
|
||||||
|
|
||||||
|
data = [self.cmd(f"B{i}<")[2] for i in range(4)]
|
||||||
|
data = b''.join(data)
|
||||||
|
page.append(data)
|
||||||
|
if len(page)==8:
|
||||||
|
if p:
|
||||||
|
page.append(p)
|
||||||
|
page = b''.join(page)
|
||||||
|
i += 1
|
||||||
|
if parity:
|
||||||
|
if bch.check_page(page):
|
||||||
|
print(f"parity error on page {i}", file=sys.stderr)
|
||||||
|
if parity == "fix":
|
||||||
|
page = self.fix_page(page)
|
||||||
|
if f and parity == "fix":
|
||||||
|
file.write(page[:512])
|
||||||
|
if not f:
|
||||||
|
result.append(page)
|
||||||
|
page = []
|
||||||
|
|
||||||
|
if f and parity != "fix":
|
||||||
|
f.write(data)
|
||||||
|
if len(page) and parity == "save":
|
||||||
|
f.write_flash(p)
|
||||||
|
if f and self.Sync:
|
||||||
|
f.sync()
|
||||||
|
|
||||||
|
if isinstance(file, str):
|
||||||
|
f.close()
|
||||||
|
return result
|
||||||
|
|
||||||
|
def fix_page(self, page):
|
||||||
|
if self.load_galois():
|
||||||
|
page = bch.fix_page(page)
|
||||||
|
|
||||||
|
def load_galois(self):
|
||||||
|
if not bch.galois:
|
||||||
|
raise bch.BCHError("galois module not loaded for Parity Error correction")
|
||||||
|
return True
|
||||||
|
|
||||||
def flags2int(FLAGS, flags):
|
def flags2int(FLAGS, flags):
|
||||||
r = 0
|
r = 0
|
||||||
|
if flags is None:
|
||||||
|
return r
|
||||||
if isinstance(flags, int):
|
if isinstance(flags, int):
|
||||||
return flags
|
return flags
|
||||||
if isinstance(flags, str):
|
if isinstance(flags, str):
|
||||||
|
|
@ -546,7 +704,7 @@ def int2flags(FLAGS, flags):
|
||||||
if tty:
|
if tty:
|
||||||
tty = dose_cmd(tty, baud)
|
tty = dose_cmd(tty, baud)
|
||||||
tty._export(globals())
|
tty._export(globals())
|
||||||
tty._verbose = False
|
tty._verbose = True
|
||||||
import dorn
|
import dorn
|
||||||
from dorn import *
|
from dorn import *
|
||||||
dorn._connect(tty)
|
dorn._connect(tty)
|
||||||
|
|
|
||||||
103
src/flash.c
103
src/flash.c
|
|
@ -150,7 +150,7 @@ uint8_t flash_cmd(uint16_t mode, uint16_t what, uint16_t page, uint16_t byte)
|
||||||
spi_start_read(csize, flash_cmd_buffer, size, b);
|
spi_start_read(csize, flash_cmd_buffer, size, b);
|
||||||
break;
|
break;
|
||||||
case FM_WAIT:
|
case FM_WAIT:
|
||||||
spi.mask = 0x80;
|
spi.mask = spi.wait = 0x80;
|
||||||
spi_start_read(csize, flash_cmd_buffer, 2, b);
|
spi_start_read(csize, flash_cmd_buffer, 2, b);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -173,7 +173,7 @@ uint8_t flash_stream_submit(uint16_t mode, uint8_t size)
|
||||||
{
|
{
|
||||||
uint8_t b = fs.block;
|
uint8_t b = fs.block;
|
||||||
uint16_t p = fs.page;
|
uint16_t p = fs.page;
|
||||||
uint8_t r = fs.status & ~FS_Ready;
|
uint8_t r = fs.status & ~FS_Ready | FS_Busy;
|
||||||
mode |= (uint16_t)config.flash_page_size << 8;
|
mode |= (uint16_t)config.flash_page_size << 8;
|
||||||
if (size) {
|
if (size) {
|
||||||
if (b & 8) {
|
if (b & 8) {
|
||||||
|
|
@ -193,21 +193,9 @@ uint8_t flash_stream_submit(uint16_t mode, uint8_t size)
|
||||||
|
|
||||||
uint8_t e = flash_cmd(mode, size, p, (uint16_t)(b&7) << 6);
|
uint8_t e = flash_cmd(mode, size, p, (uint16_t)(b&7) << 6);
|
||||||
if (e)
|
if (e)
|
||||||
r |= FS_Ready; // FS_Error
|
r |= FS_Error;
|
||||||
r |= FS_Busy;
|
|
||||||
fs.status = r;
|
fs.status = r;
|
||||||
return e;
|
return r;
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__ ((noinline, noclone))
|
|
||||||
uint8_t flash_stream_done()
|
|
||||||
{
|
|
||||||
uint8_t r = fs.status & FS_Error;
|
|
||||||
if (!r || r == FS_Error)
|
|
||||||
return 1;
|
|
||||||
if (fs.npages || !(fs.block & 8))
|
|
||||||
return 0;
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
|
|
@ -253,55 +241,50 @@ uint8_t flash_burn_page()
|
||||||
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 (rr)
|
||||||
|
r |= FS_Ack;
|
||||||
if (spi_busy_p())
|
if (spi_busy_p())
|
||||||
return r;
|
return r;
|
||||||
if ((r & FS_Error) == FS_Error)
|
if (flash_stream_done())
|
||||||
return r;
|
return r;
|
||||||
if (r & FS_StBsy) {
|
if (r & FS_Ready)
|
||||||
// status bytes arrived
|
|
||||||
if (~flash_status_bytes[0] & 0x80)
|
|
||||||
// flash is still busy burning
|
|
||||||
goto rd_status;
|
|
||||||
// not busy any more, move Bsy → Rdy
|
|
||||||
if (r & FS_Busy)
|
|
||||||
r |= FS_Ready;
|
|
||||||
goto ready;
|
|
||||||
}
|
|
||||||
if (!(r & FS_Busy))
|
|
||||||
goto ready;
|
goto ready;
|
||||||
if (rr) {
|
|
||||||
r |= FS_Error;
|
if (r & FS_StBsy && flash_status_bytes[0] & 0x80)
|
||||||
fs.status = r;
|
// flash is done burning
|
||||||
return r;
|
goto ready;
|
||||||
|
if (r & FS_Write && fs.block == 9) {
|
||||||
|
// Write or Erase
|
||||||
|
r |= FS_StBsy;
|
||||||
|
flash_status_bytes[0] = 0;
|
||||||
|
flash_cmd_na(0xd7 | FM_READ, 0xf002);
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
if (r & FS_Write) {
|
if (r & FS_Dir == FS_Write && fs.block == 8) {
|
||||||
if (fs.block == 9) {
|
// Write
|
||||||
rd_status:
|
r = flash_burn_page();
|
||||||
// request status bytes for pending Write or Error
|
goto done;
|
||||||
r |= FS_StBsy;
|
|
||||||
fs.status = r;
|
|
||||||
flash_cmd_na(0xd7 | FM_READ, 0xf002);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ready:
|
ready:
|
||||||
r &= ~(FS_Busy | FS_StBsy);
|
r &= ~(FS_Error | FS_StBsy);
|
||||||
if (rr)
|
if (!(r & FS_Ack)) {
|
||||||
r |= FS_Ack;
|
r |= FS_Ready;
|
||||||
fs.status = r;
|
goto done;
|
||||||
if (r & FS_Dir == FS_Write && fs.block == 8)
|
|
||||||
flash_burn_page();
|
|
||||||
else if (!flash_stream_done()) {
|
|
||||||
if (r & (FS_Dir|FS_Ack) == (FS_Read|FS_Ack))
|
|
||||||
flash_read_next_block();
|
|
||||||
else if (r & (FS_Dir|FS_Ack) == (FS_Write|FS_Ack))
|
|
||||||
flash_write_next_block();
|
|
||||||
else if (r & FS_Dir == FS_Erase)
|
|
||||||
flash_erase_next_page();
|
|
||||||
fs.status &=~ FS_Ack;
|
|
||||||
}
|
}
|
||||||
return fs.status;
|
r &=~ FS_Ack;
|
||||||
|
if (!fs.npages && fs.block & 8)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if ((r & FS_Dir) == FS_Read)
|
||||||
|
r = flash_read_next_block();
|
||||||
|
else if ((r & FS_Dir) == FS_Write)
|
||||||
|
r = flash_write_next_block();
|
||||||
|
else if ((r & FS_Dir) == FS_Erase)
|
||||||
|
r = flash_erase_next_page();
|
||||||
|
done:
|
||||||
|
fs.status = r;
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t flash_start_stream(uint16_t page, uint16_t npages, uint8_t flags)
|
uint8_t flash_start_stream(uint16_t page, uint16_t npages, uint8_t flags)
|
||||||
|
|
@ -310,14 +293,12 @@ uint8_t flash_start_stream(uint16_t page, uint16_t npages, uint8_t flags)
|
||||||
if ((r & FS_Error) == FS_Busy)
|
if ((r & FS_Error) == FS_Busy)
|
||||||
return FS_Error;
|
return FS_Error;
|
||||||
r = flags | FS_Ready;
|
r = flags | FS_Ready;
|
||||||
if (config.flash_page_size != FM_528)
|
|
||||||
r &=~ FS_528;
|
|
||||||
fs.page = page;
|
fs.page = page;
|
||||||
fs.block = 0;
|
|
||||||
fs.npages = npages;
|
fs.npages = npages;
|
||||||
|
flash_status_bytes[0] = 0;
|
||||||
|
fs.block = 0;
|
||||||
fs.status = r;
|
fs.status = r;
|
||||||
flash_status_bytes[0] = 0xff;
|
return r;
|
||||||
return flash_poll(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@ uint8_t flash_cmd(uint16_t mode, uint16_t what, uint16_t page, uint16_t byte);
|
||||||
extern uint8_t flash_buffer[FB_SIZE];
|
extern uint8_t flash_buffer[FB_SIZE];
|
||||||
uint8_t flash_submit_command(uint8_t *cmd);
|
uint8_t flash_submit_command(uint8_t *cmd);
|
||||||
uint8_t flash_start_stream(uint16_t page, uint16_t npages, uint8_t flags);
|
uint8_t flash_start_stream(uint16_t page, uint16_t npages, uint8_t flags);
|
||||||
uint8_t flash_stream_done();
|
|
||||||
uint8_t flash_poll(uint8_t rr);
|
uint8_t flash_poll(uint8_t rr);
|
||||||
uint16_t flash_find_free();
|
uint16_t flash_find_free();
|
||||||
|
|
||||||
|
|
@ -55,5 +54,7 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline uint8_t flash_current_block() { return fs.block; }
|
static inline uint8_t flash_current_block() { return fs.block; }
|
||||||
|
static inline uint8_t flash_stream_done()
|
||||||
|
{ return !(fs.status & FS_Error) || !(~fs.status & FS_Error); }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,6 @@ uint8_t fpga_start_read()
|
||||||
uint8_t n = 64 - pipe.fpga.val;
|
uint8_t n = 64 - pipe.fpga.val;
|
||||||
if (!n)
|
if (!n)
|
||||||
return n;
|
return n;
|
||||||
spi.rdata = flash_buffer + pipe.fpga.val;
|
|
||||||
n >>= 1;
|
n >>= 1;
|
||||||
if (~pipe.fpga.status & AS_CONT) {
|
if (~pipe.fpga.status & AS_CONT) {
|
||||||
if (!pipe.fpga.count)
|
if (!pipe.fpga.count)
|
||||||
|
|
@ -130,7 +129,10 @@ uint8_t fpga_start_read()
|
||||||
pipe.fpga.pos += n;
|
pipe.fpga.pos += n;
|
||||||
if (pipe.fpga.pos == pipe.fpga.size)
|
if (pipe.fpga.pos == pipe.fpga.size)
|
||||||
pipe.fpga.status &=~ AS_CONT;
|
pipe.fpga.status &=~ AS_CONT;
|
||||||
|
|
||||||
|
spi.rdata = flash_buffer + pipe.fpga.val;
|
||||||
spi.rsize = n << 1;
|
spi.rsize = n << 1;
|
||||||
|
spi.zsize += spi.rsize;
|
||||||
pipe.fpga.val += spi.rsize;
|
pipe.fpga.val += spi.rsize;
|
||||||
spi_start();
|
spi_start();
|
||||||
return n;
|
return n;
|
||||||
|
|
|
||||||
29
src/pipe.c
29
src/pipe.c
|
|
@ -18,7 +18,7 @@ uint8_t pipe_busy()
|
||||||
// call this with cli() before sei();sleep()
|
// call this with cli() before sei();sleep()
|
||||||
if (spi_busy_p()) return 1;
|
if (spi_busy_p()) return 1;
|
||||||
if (flash_poll(0) & FS_Busy) return 1;
|
if (flash_poll(0) & FS_Busy) return 1;
|
||||||
if (adc_poll(0)) return 1;
|
if (adc_busy()) return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,14 +77,14 @@ uint8_t pipe_poll()
|
||||||
// Return if next ADC reading is not yet due.
|
// Return if next ADC reading is not yet due.
|
||||||
// Come back here, until is is.
|
// Come back here, until is is.
|
||||||
|
|
||||||
if (pipe.source & pipe_adc && !adc_poll(pipe.adc))
|
if (pipe.source == pipe_adc && !adc_poll(pipe.adc))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
// Continue the flash stream.
|
// Continue the flash stream.
|
||||||
// PS_BLK is the 64-Bytes buffer number in the page
|
// PS_BLK is the 64-Bytes buffer number in the page
|
||||||
|
|
||||||
valid = 0;
|
valid = 0;
|
||||||
if (pipe.source & pipe_flash) {
|
if (pipe.source == pipe_flash) {
|
||||||
r &= ~ PS_BLK;
|
r &= ~ PS_BLK;
|
||||||
r |= flash_current_block() & PS_BLK;
|
r |= flash_current_block() & PS_BLK;
|
||||||
flash_poll(1);
|
flash_poll(1);
|
||||||
|
|
@ -92,9 +92,9 @@ uint8_t pipe_poll()
|
||||||
#ifdef HAVE_FPGA
|
#ifdef HAVE_FPGA
|
||||||
// Continue the FPGA stream.
|
// Continue the FPGA stream.
|
||||||
|
|
||||||
else if (pipe.source & pipe_fpga) {
|
else if (pipe.source == pipe_fpga) {
|
||||||
if (~fpga_start_read())
|
if (~fpga_start_read())
|
||||||
pipe.source &=~ pipe_fpga;
|
pipe.source = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -109,7 +109,7 @@ uint8_t pipe_poll()
|
||||||
bflgs = 0x1f;
|
bflgs = 0x1f;
|
||||||
|
|
||||||
// Data from the ADC is in named .bss segments. We send
|
// Data from the ADC is in named .bss segments. We send
|
||||||
// 16, 32, or 64 Bytes from the .bss segement for ead ADC reading.
|
// 16, 32, or 64 Bytes from the .bss segement for each ADC reading.
|
||||||
// The first named .bss segment is `magic`. Observe the link order
|
// The first named .bss segment is `magic`. Observe the link order
|
||||||
// in the Makefile.
|
// in the Makefile.
|
||||||
//
|
//
|
||||||
|
|
@ -118,7 +118,7 @@ uint8_t pipe_poll()
|
||||||
// `o` is the addr in the flash_buffer
|
// `o` is the addr in the flash_buffer
|
||||||
// `v` are the currently valid cmd_buffer flags
|
// `v` are the currently valid cmd_buffer flags
|
||||||
// `f` are the fresh valid cmd_buffer flags
|
// `f` are the fresh valid cmd_buffer flags
|
||||||
if (pipe.source & pipe_adc) {
|
if (pipe.source == pipe_adc) {
|
||||||
uint8_t n = pipe.adc & 0x70;
|
uint8_t n = pipe.adc & 0x70;
|
||||||
if (!n)
|
if (!n)
|
||||||
goto adc_done;
|
goto adc_done;
|
||||||
|
|
@ -160,11 +160,11 @@ adc_done:
|
||||||
|
|
||||||
// When the flash is done, flag the buffer valid,
|
// When the flash is done, flag the buffer valid,
|
||||||
// including BCH Bytes.
|
// including BCH Bytes.
|
||||||
if (pipe.source & pipe_flash && fs.status & FS_Ready)
|
if (pipe.source == pipe_flash && fs.status & FS_Ready)
|
||||||
valid = bflgs;
|
valid = bflgs;
|
||||||
#ifdef HAVE_FPGA
|
#ifdef HAVE_FPGA
|
||||||
// The FPGA delivers 64 Bytes.
|
// The FPGA delivers 64 Bytes.
|
||||||
else if (pipe.source & pipe_fpga && fpga_pipe_ready())
|
else if (pipe.source == pipe_fpga && fpga_pipe_ready())
|
||||||
valid = 0x0f;
|
valid = 0x0f;
|
||||||
#endif
|
#endif
|
||||||
// The buffer is not here, yet. Nothing we can do now.
|
// The buffer is not here, yet. Nothing we can do now.
|
||||||
|
|
@ -181,10 +181,10 @@ adc_done:
|
||||||
// Last buffer of the page:
|
// Last buffer of the page:
|
||||||
if (!(~r & PS_BLK)) {
|
if (!(~r & PS_BLK)) {
|
||||||
bch4369_fini();
|
bch4369_fini();
|
||||||
valid = 0x01f;
|
|
||||||
// When the Flash is not the source,
|
// When the Flash is not the source,
|
||||||
|
// and cmd did not provide the parity
|
||||||
// copy the computed parity into the buffer.
|
// copy the computed parity into the buffer.
|
||||||
if (~pipe.source & pipe_flash)
|
if (~valid & 0x10)
|
||||||
_memcopyyz(bend, bch_parity, 16);
|
_memcopyyz(bend, bch_parity, 16);
|
||||||
// When the page as read from flash has invalid parity,
|
// When the page as read from flash has invalid parity,
|
||||||
// stop writing to the FPGA.
|
// stop writing to the FPGA.
|
||||||
|
|
@ -192,6 +192,7 @@ adc_done:
|
||||||
dest &=~ pipe_fpga;
|
dest &=~ pipe_fpga;
|
||||||
r |= PS_ERR;
|
r |= PS_ERR;
|
||||||
}
|
}
|
||||||
|
valid = 0x1f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We still do not have all data we need
|
// We still do not have all data we need
|
||||||
|
|
@ -203,7 +204,7 @@ adc_done:
|
||||||
|
|
||||||
#ifdef HAVE_FPGA
|
#ifdef HAVE_FPGA
|
||||||
// Resume the FPGA stream
|
// Resume the FPGA stream
|
||||||
if (dest & pipe_fpga & ~fpga_start_write())
|
if (dest & pipe_fpga && ~fpga_start_write())
|
||||||
dest &=~ pipe_fpga;
|
dest &=~ pipe_fpga;
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -227,7 +228,7 @@ void pipe_config(const struct pipe_config *c, const struct pipe_fpga_cmd *a)
|
||||||
{
|
{
|
||||||
/************************************************************
|
/************************************************************
|
||||||
* cmd("B0!", «fpga-cmd») optionally configure an FPGA cmd
|
* cmd("B0!", «fpga-cmd») optionally configure an FPGA cmd
|
||||||
* cmd("P0:, «pipe-cfg») with `AS_CMD` in `.status`
|
* cmd("P0", «pipe-cfg») with `AS_CMD` in `.status`
|
||||||
***********************************************************/
|
***********************************************************/
|
||||||
|
|
||||||
if (c->pipe.dest) {
|
if (c->pipe.dest) {
|
||||||
|
|
@ -238,6 +239,7 @@ void pipe_config(const struct pipe_config *c, const struct pipe_fpga_cmd *a)
|
||||||
else {
|
else {
|
||||||
// new source (NOT flash)
|
// new source (NOT flash)
|
||||||
pipe.source = c->pipe.source;
|
pipe.source = c->pipe.source;
|
||||||
|
pipe.adc = c->pipe.adc;
|
||||||
}
|
}
|
||||||
if (pipe.source & pipe_adc)
|
if (pipe.source & pipe_adc)
|
||||||
adc_start_stream(pipe.adc);
|
adc_start_stream(pipe.adc);
|
||||||
|
|
@ -247,6 +249,7 @@ void pipe_config(const struct pipe_config *c, const struct pipe_fpga_cmd *a)
|
||||||
_memcopyzy((void*)&pipe_fpga_cmd, (void*)a, sizeof(*a));
|
_memcopyzy((void*)&pipe_fpga_cmd, (void*)a, sizeof(*a));
|
||||||
else
|
else
|
||||||
memset(&pipe_fpga_cmd, 0, sizeof(*a));
|
memset(&pipe_fpga_cmd, 0, sizeof(*a));
|
||||||
|
pipe.fpga = c->pipe.fpga;
|
||||||
fpga_start_read();
|
fpga_start_read();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
17
src/spi.c
17
src/spi.c
|
|
@ -387,23 +387,18 @@ ISR(SPI0_INT_vect, ISR_NAKED)
|
||||||
"rjmp 4f" "\n"
|
"rjmp 4f" "\n"
|
||||||
|
|
||||||
"1:" "\n\t"
|
"1:" "\n\t"
|
||||||
"lds r26, %[MASK]" "\n\t"
|
"lds r26, %[WAIT]" "\n\t"
|
||||||
"cpi r26, 0" "\n\t"
|
"eor r26, r25" "\n\t"
|
||||||
"breq 1f" "\n\t"
|
"lds r24, %[MASK]" "\n\t"
|
||||||
"and r26, r25" "\n\t"
|
"and r26, r24" "\n\t"
|
||||||
"lds r24, %[WAIT]" "\n\t"
|
"breq 2f" "\n\t"
|
||||||
"cp r24, r26" "\n\t"
|
|
||||||
"brne 2f" "\n\t"
|
|
||||||
"lds r25, %[ZSZ]" "\n\t"
|
"lds r25, %[ZSZ]" "\n\t"
|
||||||
"subi r25, -1" "\n\t"
|
"subi r25, -1" "\n\t"
|
||||||
"sts %[ZSZ], r25" "\n\t"
|
"sts %[ZSZ], r25" "\n\t"
|
||||||
"rjmp 4f" "\n"
|
"rjmp 4f" "\n"
|
||||||
|
|
||||||
"2:" "\n\t"
|
"2:" "\n\t"
|
||||||
"clr r26" "\n\t"
|
"sts %[MASK], r26" "\n\t"
|
||||||
"sts %[MASK], r26" "\n"
|
|
||||||
|
|
||||||
"1:" "\n\t"
|
|
||||||
"lds r26, %[RSZ]" "\n\t"
|
"lds r26, %[RSZ]" "\n\t"
|
||||||
"subi r26, 1" "\n\t"
|
"subi r26, 1" "\n\t"
|
||||||
"brcs 4f" "\n\t"
|
"brcs 4f" "\n\t"
|
||||||
|
|
|
||||||
14
src/thhor.c
14
src/thhor.c
|
|
@ -13,6 +13,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
#include "pipe.h"
|
#include "pipe.h"
|
||||||
|
#include "adc.h"
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
|
|
@ -40,17 +41,18 @@ int main()
|
||||||
send_hex_byte_eol(magic.reset_source);
|
send_hex_byte_eol(magic.reset_source);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
// The pipe may become idle before we reach sleep.
|
// The irq sources may become idle before we reach sleep.
|
||||||
// Make sure we have nothing to do before we sleep.
|
// Make sure we have nothing pending before we sleep.
|
||||||
// The sleep command will execute even when an irq
|
// The sleep command will execute even when an irq becomes
|
||||||
// is pending. It will wake us immediately.
|
// pending after cli(). It will wake us immediately.
|
||||||
cli();
|
cli();
|
||||||
if (!command_pending() && (!pipe.dest || pipe_busy())) {
|
if (!command_pending() || adc_busy() || spi_busy_p()) {
|
||||||
sei();
|
sei();
|
||||||
sleep_cpu();
|
sleep_cpu();
|
||||||
}
|
}
|
||||||
sei();
|
sei();
|
||||||
command();
|
command();
|
||||||
pipe_poll();
|
if (~magic.flags & hold_pipe)
|
||||||
|
pipe_poll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ class uart(threading.Thread):
|
||||||
|
|
||||||
def parse_line(self, l):
|
def parse_line(self, l):
|
||||||
self.responses.append(l)
|
self.responses.append(l)
|
||||||
if self._verbose:
|
if self._verbose >= 4:
|
||||||
try:
|
try:
|
||||||
s = l.decode()
|
s = l.decode()
|
||||||
print(f"{self.portname}<- {s}", file=sys.stderr)
|
print(f"{self.portname}<- {s}", file=sys.stderr)
|
||||||
|
|
@ -92,7 +92,7 @@ class uart(threading.Thread):
|
||||||
c = c.encode()
|
c = c.encode()
|
||||||
if c[-1:] != b'\n':
|
if c[-1:] != b'\n':
|
||||||
c = c + b'\n'
|
c = c + b'\n'
|
||||||
if self._verbose:
|
if self._verbose >= 4:
|
||||||
print(f"{self.portname}-> {c.decode().rstrip()}", file=sys.stderr)
|
print(f"{self.portname}-> {c.decode().rstrip()}", file=sys.stderr)
|
||||||
self.write(c)
|
self.write(c)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue