diff --git a/doc/load-run-code.md b/doc/load-run-code.md index db18c25..9ea3abf 100644 --- a/doc/load-run-code.md +++ b/doc/load-run-code.md @@ -2,7 +2,7 @@ Collapse OS likely runs from ROM code. If you need to fiddle with your machine more deeply, you will want to send arbitrary code to it and run it. You can do -so with the shell's `load` and `call` commands. +so with the shell's `poke` and `call` commands. For example, let's say that you want to run this simple code that you have sitting on your "modern" machine and want to execute on your running Collapse OS @@ -22,7 +22,7 @@ Now, we'll send that code to address `0xa000`: > mptr a000 A000 - > load 8 (resulting binary is 8 bytes long) + > poke 8 (resulting binary is 8 bytes long) Now, at this point, it's a bit delicate. To pipe your binary to your serial connection, you have to close `screen` with CTRL+A then `:quit` to free your @@ -31,7 +31,7 @@ tty device. Then, you can run: cat tosend.bin > /dev/ttyUSB0 (or whatever is your device) You can then re-open your connection with screen. You'll have a blank screen, -but if the number of characters sent corresponds to what you gave `load`, then +but if the number of characters sent corresponds to what you gave `poke`, then Collapse OS will be waiting for a new command. Go ahead, verify that the transfer was successful with: @@ -62,16 +62,19 @@ Success! The serial connection is not always 100% reliable and a bad byte can slip in when you push your code and that's not fun when you try to debug your code (is -this bad behavior caused by my logic or by a bad serial upload?). +this bad behavior caused by my logic or by a bad serial upload?). Moreover, +sending contents bigger than `0xff` bytes can be a hassle. To this end, there is a `upload.py` file in `tools/` that takes care of loading -the file and verify the contents. So, instead of doing `load 8` followed by -your `cat` above, you would have done: +the file and verify the contents. So, instead of doing `mptr a000` followed by +`poke 8` followed by your `cat` above, you would have done: - ./upload.py /dev/ttyUSB0 tosend.bin + ./upload.py /dev/ttyUSB0 a000 tosend.bin -This emits `load` and `peek` commands and fail appropriately if the `peek` -doesn't match sent contents. Very handy. +This emits `mptr`, `poke` and `peek` commands and fail appropriately if the +`peek` doesn't match sent contents. If the file is larger than `0xff` bytes, +repeat the process until the whole file was sent (file must fit in memory space +though, of course). Very handy. ## Labels in RAM code diff --git a/tools/upload.py b/tools/upload.py index 58f0931..115ae89 100755 --- a/tools/upload.py +++ b/tools/upload.py @@ -24,41 +24,60 @@ def sendcmd(fd, cmd): def main(): parser = argparse.ArgumentParser() parser.add_argument('device') + parser.add_argument('memptr') parser.add_argument('filename') args = parser.parse_args() + try: + memptr = int('0x' + args.memptr, 0) + except ValueError: + print("memptr are has to be hexadecimal without prefix.") + return 1 + if memptr >= 0x10000: + print("memptr out of range.") + return 1 + maxsize = 0x10000 - memptr st = os.stat(args.filename) - if st.st_size > 0xff: - print("File too big. 0xff bytes max") + if st.st_size > maxsize: + print("File too big. 0x{:04x} bytes max".format(maxsize)) return 1 fd = os.open(args.device, os.O_RDWR) - sendcmd(fd, 'poke {:x}'.format(st.st_size).encode()) - print("Poking...") with open(args.filename, 'rb') as fp: - fcontents = fp.read() - for c in fcontents: - os.write(fd, bytes([c])) - # Let's give the machine a bit of time to breathe. We ain't in a - # hurry now, are we? - time.sleep(0.0001) - print("Poked") - os.read(fd, 5) - print("Peeking back...") - sendcmd(fd, 'peek {:x}'.format(st.st_size).encode()) - peek = b'' - while len(peek) < st.st_size * 2: - peek += os.read(fd, 1) - time.sleep(0.0001) + while True: + fcontents = fp.read(0xff) + if not fcontents: + break + print("Seeking...") + sendcmd(fd, 'mptr {:04x}'.format(memptr).encode()) + os.read(fd, 9) + sendcmd(fd, 'poke {:x}'.format(len(fcontents)).encode()) + print("Poking...") + for c in fcontents: + os.write(fd, bytes([c])) + # Let's give the machine a bit of time to breathe. We ain't in a + # hurry now, are we? + time.sleep(0.0001) + print("Poked") + os.read(fd, 5) + print("Peeking back...") + sendcmd(fd, 'peek {:x}'.format(len(fcontents)).encode()) + peek = b'' + while len(peek) < len(fcontents) * 2: + peek += os.read(fd, 1) + time.sleep(0.0001) + os.read(fd, 5) + print("Got {}".format(peek.decode())) + print("Comparing...") + for i, c in enumerate(fcontents): + hexfmt = '{:02X}'.format(c).encode() + if hexfmt != peek[:2]: + print("Mismatch at byte {}! {} != {}".format(i, peek[:2], hexfmt)) + return 1 + peek = peek[2:] + print("All good!") + memptr += len(fcontents) + print("Done!") os.close(fd) - print("Got {}".format(peek.decode())) - print("Comparing...") - for i, c in enumerate(fcontents): - hexfmt = '{:02X}'.format(c).encode() - if hexfmt != peek[:2]: - print("Mismatch at byte {}! {} != {}".format(i, peek[:2], hexfmt)) - return 1 - peek = peek[2:] - print("All good!") return 0 if __name__ == '__main__':