I had a marathon hacking session this weekend and added a lot of improvements and new features to z80ctrl:
- Massive reduction in memory usage. FatFS had a default configuration that used a separate buffer for each file object. I had 16 static file objects for the drive emulation. After I found the configuration option to switch to shared buffers, along with some other changes such as moving all the strings in my code to flash, static RAM usage on the AVR went from 77% down to 17%. Memory usage will still go up and down as variable are allocated on the stack in certain functions, but 17% is now the baseline. A 77% baseline was dangerously close to running out of memory if a function was run that allocated a big array on the stack.
- Switch to using BUSRQ to negotiate handing the data bus back to the Z80 after an IORQ instead controlling the clock in software. Manually clocking was interfering with other peripherals like Ed Brindley's sound card that rely on a steady clock rate. This resulted in audible pops when the AVR was answering IORQs. Now it plays without any glitches. I got the idea to use BUSRQ in this way from Just4fun's AVR/Z80 project.
- Switch to an interrupt-driven buffered UART driver. This makes it much less likely that the AVR will lose characters when the PC is sending it data quickly. It's still possible to overrun the buffers using PuTTY but it's a lot better than it was. Copy and Pasting via TeraTerm now seems to work pretty well, and XMODEM transfers work as long as the baud rate is 115200 or less. Slower baud rates are less likely to overrun the buffer. As the AVR doesn't have any hardware flow control, this is probably the best I can do to solve this problem.
- Change to a columnar directory listing a la CP/M or Unix ls, instead of one file per line used before.
- Dual UART support as demonstrated in the screenshot. Either physical UART can be assigned to either of two virtual UARTs available to the Z80. So, for example, you can have debugging output from z80ctrl monitor on UART 0, and interact with the Z80 on UART 1. The default virtual to physical mapping is 0 to 0 and 1 to 1. This can be changed using the "attach" monitor command.
- Run-time configurable baud rate. The default rate is still 115200 but it can be changed on the fly using the "baud" command. After you enter the command, it calculates the closest actual baud rate the AVR can achieve and prints it out. It flushes the buffer before switching baud rate so that the output doesn't get corrupted by the baud rate change. You will have to change your terminal's baud rate before you can interact any further. I've tested baud rates from 600 bps all the way up to 1.25Mbps successfully. You can also configure a custom baud rate at startup using the autoexec functionality (see below).
- Figured out how to get libc-avr's stdio library working with fatfs, which gives me the ability to transparently use a file in place of stdin, stdout, or stderr. This lays the groundwork for a lot of nice features, the first of which is batch files. Other potential features are the ability to redirect errors to a separate terminal, log debugging info to a file, redirect command output to a file, and so on.
- Batch files! You can now place text files on your SD card with one z80ctrl monitor command per line and then execute them via the "submit" monitor command. This is very simple, just a list of commands to execute verbatim--no flow control, variables, etc. If you place a file named autoexec.z8c in the root directory of your SD card, z80ctrl will execute it automatically upon startup. This is a nice way to configure your baud rate, attach virtual UARTs, mount drives, even boot CP/M automatically.
- Run-time configurable Z80 clock rate via the "clkdiv" monitor command. Any number 1-255 can be specifie for clkdiv. One of the PWM's output compare registers is set to the clkdiv value and the other is set to half the clkdiv value, so that the clock remains as close to 50% duty cycle as possible. This implementation means the clkdiv isn't a straightforward divider. clkdiv=2 results in a 6.67MHz, not 5MHz as you might expect.
- Minor bugfixes here and there.
- Lots of code refactoring, cleanup, and documentation.
All of these changes have been pushed to GitHub. Check them out!