The FlashCART is a version of the MegaCART with flash ROM. Its main purpose is to act as a simple development environment for the MegaCART. You can upload a program from a PC through a RS-232C port and store it on the FlashCART. It is also possible to use the serial port in your own programs, for example in my Videopac+ graphics editor. The communication protocol is designed to work with USB to serial converters without much speed loss.
The FlashCART is a MegaCART with a flash ROM instead of the EPROM. Additionally there is a firmware EPROM which handles the communication protocol. Which one is used is decided by a switch. There is also a RS-232C port with level translator. Command packets are read on the T0 line of the 8048 processor. The answers are sent on one of the I/O ports. The communication parameters are 38400 bps, 8 bits, 1 stop bit, no parity. It is possible to use this port in your own programs. My VPP graphics editor example program uses it to save and load the VPP screens.
This is a picture of a FlashCART. Click on it for a bigger picture. This is
version 1.1, the version you can download below. I left out the EEPROM
on this one to play with the expansion port.
The FlashCART has 1 Mbyte of non-volatile flash ROM. That means that it keeps its data even without power. So you can copy a program onto it at home and take the FlashCART to a friend to show your latest programming efforts without having to take your PC with you.
The FlashCART has a normal 9 pin female RS-232C COM port connector. You need a normal serial 1:1 extension cable to connect it to a PC with a serial port. This cable is a different one than the cable for my RAM cart.
If your PC does no longer have a serial port or they are already in use you can also get a USB to serial converter. I recommend one with a cable already attached, so you don't have to get another cable to connect the converter to the FlashCART. I personally like converters built with FTDI chips, since their drivers allow some fine tuning, but it is not always mentioned which chips are inside the converters.
It is also possible to use a Bluetooth to serial converter. The one I tested is much slower than a real cable and has a higher error rate. To get it to work I had to change the MTU to 136 to avoid packet fragmentation in the air.
The FlashCART has a switch to change between communication mode and run mode. In communication mode the FlashCART talks to the PC and gets its memory filled. In run mode the program you sent to the FlashCART runs on the Videopac. You can switch between modes with the switch connected to the SWITCH1 connector. To change modes hold RESET, toggle the switch and release RESET. It is safe to toggle the switch without pressing RESET if you are in communication mode and have sent the --endcomm command. You will see the message "READY FOR RESET" on the Videopac screen. You still need to press RESET to start your program after you changed the switch.
In communication mode the firmware in the EPROM is active. Press any key after RESET to start. You will see a black screen with the version number of the firmware and a P for PAL or N for NTSC in the top right corner. The Videopac is listening for commands on the serial port. Use the g7kflash program to talk to it. A full program upload to the FlashCART takes between 10 and 11 minutes. If you finished uploading use the --endcomm command, toggle the switch, press RESET and the program you sent to the FlashCART starts at 0400h in bank 0ffh, flash address 0xff400.
The communication program that I have written is a simple command line tool. It should not be difficult to create a GUI for it or even integrate it into a development environment. The program is portable to different Operation Systems, I provide ports to Linux, Windows, AmigaOS and NetBSD.
G7kflash takes one command and several parameters. Here are the possible parameters and what they mean:
This is the device where the FlashCART is connected to. The exact name depends on the OS you use, examples are /dev/ttyS0 or /dev/ttyUSB0 for Linux, COM1 or \\.\COM10 for Windows, serial.device/0 for AmigaOS or /dev/dty00 for NetBSD.
This is the first address for the flash and EEPROM access commands that is used.
This is the last address for the flash and EEPROM access commands that is used.
This is the position of the first byte that is read/written to in the file for the flash and EEPROM access commands. This is not fully supported on all Operation Systems.
Suppress the progress information for the EEPROM and flash commands.
Prints some more information about what is going on for the --linetest command.
Dump all the communication between PC and FlashCART, only useful for debugging the protocol.
And here are the commands for g7kflash:
Prints a short explanation of all parameters and commands.
Tests the communication between PC and FlashCART by sending num
NOP data packets and checking the answers. It can be used to check the
stability of the communication, although its main use was to help porting and
debugging the low-level communication routines.
Sends a special command to end all communication between PC and FlashCART. The normal firmware jumps to an endless loop in the BIOS so you can switch to the program without holding down RESET. Integrated firmware can react different, the VPP editor uses it to jump back from communication mode into main mode.
Identifies the flash and EEPROM chips. The EEPROM identification can't distinguish the 93C56/93C66 and the 93C76/93C86 because they are nearly identical in use.
Erase the flash sector at adr or the whole chip if
adr is 0xffffff. This operation can take a lot of time,
the timeout chosen by g7kflash is displayed on screen. The timeout depends on
the flash chip used. The exact sector layout depends on the flash chip used,
please look into the datasheet for the flash chip you have.
Write the file file to flash ROM. Use a filename of
- for the standard input. To change the address to write to in
flash ROM use the --start parameter. You can only change 1 bits to 0 bits when
writing to flash ROM, so if there is already data there you need to erase it
first.
Read from flash ROM to the file file. Use a filename of
- for the standard output. To change the address to read from in
flash ROM use the --start parameter.
Erase the whole EEPROM.
Write the file file to EEPROM. Use a filename of -
for the standard input. To change the address to write to in EEPROM use the
--start parameter. The EEPROM can be overwritten without erasing.
Read from EEPROM to the file file. Use a filename of
- for the standard output. To change the address to read from in
EEPROM use the --start parameter.
Read from the VPP screen to the file file. All char, attribute
and slice data are copied. The resulting file is identical to the result from
the savevpp command in O2EM's debugger (note that the savevpp command is broken
in O2EM 1.17.3 and 1.18): First there are 25 lines starting with line 0 and
ending with the service row. Then there are 960 bytes for slice data
without background and another 960 bytes of slice data with background
change. This command is mostly useful for saving the screens from the VPP screen
editor.
Write back the file file saved with --readvpp to the VPP screen.
This command is mostly useful for the VPP screen
editor.
The normal serial ports are called /dev/ttySX on Linux/i386. The
USB converters usually show up as /dev/ttyUSBX. You may need
special rights to access these devices as normal user, see the manual of your
distribution for details. You either need to add your user id to a specific
group or change the udev configuration to allow access. You can fine tune some
of the FTDI converters by changing the latency setting via the /sys filesystem
to 1. This only works on kernel 2.6.22 or newer.
The binary was compiled on a Debian 4.0 etch distribution.
The normal serial ports and the USB converters both show up as
COMX. For X>=10 you need to use the full resource
path to access it: "\\.\COM10". You can fine-tune USB converters by setting the
latency to 1ms and changing the buffer sizes to the smallest
number >=136.
The binary was cross-compiled with mingw-gcc 3.4.1.
The normal serial port is serial.device/0. The --filestart parameter only works on writing if the file is already big enough.
The binary was compiled on AmigaOS 3.1 with dice 3.16 on an Amiga 4000 with 68030. It is also tested on AmigaOS 2.0 on a plain Amiga 2000.
The normal serial ports are called /dev/dty0X. The USB converters
show up as /dev/ttyUX.
The binary was compiled on NetBSD 3.1.
The communication protocol is based on a standard serial communication with 38400 bits per second, 8 bits, no parity, one stop bit. It is packet-based with 8 header bytes and up to 128 bytes of data. The FlashCART is completely passive, it waits for a command packet, executes the command and returns an answer packet, it never sends any data without being asked.
| iram_hd_len | Length of data field |
|---|---|
| iram_hd_cmd | Command to execute |
| iram_hd_adrh | High byte of the address |
| iram_hd_adrm | Middle byte of the address |
| iram_hd_adrl | Low byte of the address |
| iram_hd_hsum | Header checksum: add first 5 byte of header without carry |
| iram_hd_dsumh | High byte of data checksum: add iram_hd_len bytes of data without carry |
| iram_hd_dsuml | Low byte of data checksum: add iram_hd_len bytes of data without carry |
Most of the commands need an address as parameter, so there is a 24 bit address in the header. The checksums are just a sum without carry bit of all relevant bytes in 8 bit for the header and 16 bit for the data. Better checksums take much longer to compute on the FlashCART side, so I had to choose simple ones.
All commands have the highest bit 7 cleared. When answering the FlashCART sets this bit. If any of the checksums do not match in the answer packet a reception error occurred. Try to repeat the offending command to make sure it is executed correctly. If the checksums are ok, the highest bit of the command is set and the lower 7 bits still contain the command then the command was executed successfully.
The FlashCART can return several error codes, all have the highest bit set without a matching command:
| 0F6h | CMD_ERR_NOCMD | The command is not known to the FlashCART |
|---|---|---|
| 0F7h | CMD_ERR_NOEEP | No EEPROM was found |
| 0F8h | CMD_ERR_REFUSE | The FlashCART refuses to execute this command |
| 0F9h | CMD_ERR_NOVPP | This command only works on a Videopac+ machine |
| 0FAh | CMD_ERR_ERASE | An erase did not complete |
| 0FBh | CMD_ERR_VRFY | A byte was not written correctly |
| 0FCh | CMD_ERR_WRITE | A write failed |
| 0FDh | CMD_ERR_HSUM | The header checksum did not match |
| 0FEh | CMD_ERR_DSUM | The data checksum did not match |
| 0FFh | CMD_ERR_TIME | Timeout while receiving data on the FlashCART |
Although the CMD_ERR_VRFY and CMD_ERR_WRITE sound
similar they have a different meaning. CMD_ERR_WRITE means that the
flash ROM chip returned an error while writing. CMD_ERR_VRFY means
that the flash ROM chip thinks the write was ok, but that the FlashCART found a
different byte than expected.
CMD_NOP: do nothingThis command just sends all data it receives back to the PC. It is used for presence detection and for --linetest.
CMD_FIRMWARE: return firmware versionThis command returns 2 bytes of data: The major and the minor version number.
They are the same as with the commapi_version API call.
CMD_END: end the communicationThis command is used to end the communication. On the FlashCART it prints "READY FOR RESET" and jumps to an endless loop. If you insert the firmware into one of your own projects you should replace this with something that makes more sense for you. This command is used for --endcomm.
CMD_FLS_RD: read from the flash ROMThis command reads a block from flash ROM starting at the supplied address and sends it to the PC. It takes the number of bytes to read as an additional parameter in the first data byte. The number of bytes has to be <=128. The whole block has to be in the same page.
CMD_FLS_WR: write to the flash ROMThis command writes iram_hd_len bytes into the flash ROM
starting at the address in the header. The number of bytes has to be <=128.
The whole block has to be in the same page. This command handles the full write
cycle with flash ROM unlocking, writing and data polling for every byte. You
can't use this command if you insert the firmware into your own programs.
CMD_FLS_ER: erase a sector or all of the
flash ROMThis commands erases the flash sector at the header address or the whole chip when the address is 0xffffff. This command handles the full erase cycle with flash ROM unlocking, erasing and data polling. It can take a long time to execute, especially as the flash ROM chip ages. See the datasheet of the flash ROM in your FlashCART for details. You can't use this command if you insert the firmware into your own programs.
CMD_FLS_ID: return the flash ROM idEvery modern flash chip has a manufacturer and a device id. This command returns both in the data field, first the manufacturer then the device id. See datasheets of flash ROM chips for the possible ids. You can't use this command if you insert the firmware into your own programs.
CMD_FLS_DWR: direct writeThis command allows you to send write commands directly to the flash ROM.
There will be no unlock cycles, just writes to the flash ROM. So you can use all
commands the flash ROM allows. Usually these commands will be single byte
writes. The parameters are the same as for CMD_FLS_WR. This command
is not used by g7kflash. You can't use this command if you insert the firmware
into your own programs.
CMD_EEP_RD: read from EEPROMThis command reads a block from the EEPROM and sends it to the PC. The number of bytes to read is in the first data byte. It has to be <=128. Only up to 16 bits of the address are used. The biggest EEPROM only has 11 active address bits, so this is not a really a restriction.
CMD_EEP_WR: write to EEPROMThis command writes iram_hd_len bytes into the EEPROM starting
at the address in the header. The number of bytes has to be <=128. Only up to
16 bits of the address are used.
CMD_EEP_ER: erase EEPROMThis command erases the whole EEPROM. Since any byte can be written directly there is no byte erase implemented.
CMD_EEP_ID: return the EEPROM address
lengthThis commands return in one data byte the number of address bits the EEPROM has.
CMD_VDC_WR: write to VDCThis command writes a data block into the VDC starting with the address in the header. Only the lowest 8 bits of the address are used. This command is not used by g7kflash. There is no corresponding read command.
CMD_VPP_RD: read from VPP screenThis command reads char and attribute data from the Videopac+ screen. The addresses are not linear, the position is encoded into the middle and low address byte. The middle address byte contains the line number as used by the Videopac+, so the service row is 31. Only 5 bits of the line number are used. The lowest address byte contains the X position in bits 7-1, bit 0 is unused. This encoding makes sense since there are two byte for every position: the char and the attribute byte. The length in the first data byte is still in bytes, not number of char positions. All data to read should be in the same line.
CMD_VPP_WR: write to VPP screenThis command write char and attribute data to the Videopac+ screen. The addresses are not linear, the position is encoded into the middle and low address byte. The middle address byte contains the line number as used by the Videopac+, so the service row is 31. Only 5 bits of the line number are used. The lowest address byte contains the X position in bits 7-1, bit 0 is unused. This encoding makes sense since there are two byte for every position: the char and the attribute byte. The length in the header is the number of bytes to write, not the number of char positions. All data to read should be in the same line.
CMD_VPP_RDSL: read VPP slice dataThis commands reads from the Videopac+ redefined chars. The lowest address byte contains the first char to read. The lowest bit of the middle address byte contains a flag which set of redefined chars is used: 0 for the normal set and 1 for the chars with background as parallel attribute. The length byte in the first data byte contains the number of bytes to read. You should only read complete chars, the length should be multiplies of 10 bytes of slice data. The length has to be <=128.
CMD_VPP_WRSL: write VPP slice dataThis commands writes to the Videopac+ redefined chars. The lowest address byte contains the first char to write to. The lowest bit of the middle address byte contains a flag which set of redefined chars is used: 0 for the normal set and 1 for the chars with background as parallel attribute. The length byte in the header contains the number of bytes to write. You should only write complete chars, the length should be multiplies of 10 bytes of slice data. The length has to be <=128.
CMD_VPP_MODE: call plusmodeThis command sets the VPP mode. It calls plusmode with the first data byte as transparency and the second data byte as luminance. This command is not used in g7kflash.
CMD_VPP_CMD: call pluscmdThis command sends any command to the VPP. It calls pluscmd with the first data byte as command and the second data byte as parameter. This command is not used in g7kflash.
If you want to add your own commands please use the range from 060h-06fh. If you think your extensions are useful for other people, too, then contact me so I can reserve some commands for you and add them officially to the protocol.
The firmware which handles all the communication can also be used in your own programs. To be able to do that you have to include a copy of the firmware into your own program, there is no way to access the EPROM used for running the firmware in download mode. This also means that you can't do any write accesses to the flash ROM since the code is running from there. The firmware contains routines for initialisation, for communication with a PC and EEPROM routines.
The firmware needs addresses 0500h-0fffh in any code bank. The page from 0400h-04ffh is free to allow you to interface the rest of the program with the firmware. Try to use the interface documented here whenever possible, this makes it easier to update the firmware when I release updates. Don't rely on anything that I don't document here, for example preserved registers.
Some of my example programs use the firmware API. The most complex one is the VPP screen editor. A much simpler program is the EEPROM editor.
You can download an include file with all symbolic names used, it is called the flashdefs.h include file.
All routines expect that bits 0, 1 and 2 of address 03Fh are set to the
correct machine type, see commapi_init for explanations. The
routines commapi_readblock and commapi_execcmd use
internal RAM from 020h-027h:
| 03Fh | iram_mode | Some flags for the firmware |
| 03Fh:0 | iram_mode_plus | 1=Machine is a Videopac+ |
| 03Fh:1 | iram_mode_pal | 1=Machine has PAL timings |
| 03Fh:2 | iram_mode_local | 1=Command is locally created |
| 020h | iram_hd_len | Length of data field |
| 021h | iram_hd_cmd | Command to execute |
| 022h | iram_hd_adrh | Highest byte of address |
| 023h | iram_hd_adrm | Middle byte of address |
| 024h | iram_hd_adrl | Lowest byte of address |
| 025h | iram_hd_hsum | Header checksum |
| 026h | iram_hd_dsumh | High byte of data checksum |
| 027h | iram_hd_dsuml | Low byte of data checksum |
The routines commapi_readblock and the
commapi_execcmd may overwrite any external RAM.
All routines have fixed entry points at the beginning of the firmware code.
When finished all use ret to return to the caller with sel
mb0 active.
commapi_initThis routine initialises the firmware: It disables the EEPROM, resets the
flash ROM chip, turns off XROM and sets the iram_mode_plus and
iram_mode_pal bits. When assembled for debugging it will also print
a version number on the Videopac+ screen. It does not touch the
code bank switching. The reason is simple: In most cases you have already
used it to get to the firmware bank.
| Input | IRQ chain with a working waitvsync |
|---|---|
| Output | iram_mode is set to the detected machine type |
| EEPROM and flash ROM are in a defined state | |
| The TX line is ready for communication | |
| The external RAM is enabled | |
| Alters | Everything |
The machine type bit iram_mode_pal is set when the machine runs
with PAL timings. The iram_mode_plus is set when the machine has a
Videopac+ BIOS. Both bit definitions define the bit number, not
a bit mask, use (1 << iram_mode_X) to get the bit mask for
testing if a bit is set. All other bits in iram_mode except the two
highest bits are cleared.
commapi_versionThis routine returns two version numbers for the firmware itself. Both are BCD coded numbers. All changes to the API defined here will change the major version number. The minor version number will change with every release I make.
| Input | None |
|---|---|
| Output | R6: major version number |
| R7: minor version number |
commapi_readblockThis routines waits until the PC sends data. Once a data block is complete
the checksums are checked and a return code is generated. The command received
is not executed. This allows protocol extensions and redefinitions, you will
quite likely redefine the CMD_END command to return to the program
into which you include this firmware.
| Input | extramenable |
|---|---|
| Output | A=RET_OK data block ok |
| A=RET_TIMEOUT data block incomplete | |
| A=RET_HSUM header checksum mismatch | |
| A=RET_DSUM data checksum mismatch | |
| iram(020h-027h): header | |
| extram: data | |
| interrupts enabled | |
| Alters | Everything |
commapi_execcmdThis routine executes a command received by commapi_readblock
and sends an answer to the PC. In the case of reception errors it sends the
correct error code back to the PC, the command is not executed.
It is also possible to execute a command locally without a PC present. You
have to set the iram_mode_local bit for that. You also have to
prepare a header and the data as if they were sent from a PC except the
checksums.
This routine is special, it returns with interrupts disabled. This is needed
to reliably receive the next command after the current one is answered. The PC
expects that the firmware is ready to receive immediately after the PC got the
answer from a command. Any interrupt running at that time will lead to lost
bytes. So use en i if you return to your normal program after
running commapi_execcmd.
| Input | extramenable |
|---|---|
A: return code from commapi_readblock | |
| iram(020h-027h): header | |
| extram: data | |
| Output | interrupts disabled |
| iram(020h-027h): answer header | |
| extram: answer data | |
| Alters | Everything |
commapi_eepromsizeThis routine returns the number of address bits used by the EEPROM. For some EEPROMs (93C56, 93C76) the highest address bit is a don't care bit. The only way to detect that is to write different data to two locations differing only on the highest address bit and to read back from the first location to see if it has changed by the second write.
| Input | extramenable |
|---|---|
| Output | A: number of address bits, 0 for no EEPROM |
| Alters | R0 R2 R3 R6 R7 |
commapi_eepromreadThis routines reads one byte from the EEPROM. To read lots of bytes at once
use commapi_execcmd with the CMD_EEP_RD command.
| Input | extramenable |
|---|---|
| R5: high byte of address | |
| R6: low byte of address | |
| Output | A: byte read from EEPROM |
| Alters | A R0 R2 R5 R6 R7 |
commapi_eepromwriteThis routine writes one byte to the EEPROM. To write lots of bytes at once
use commapi_execcmd with the CMD_EEP_WR command.
| Input | extramenable |
|---|---|
| R5: high byte of address | |
| R6: low byte of address | |
| A: data byte to write | |
| Output | A=0 ok |
| A=0ffh write error | |
| Alters | A R0 R2 R3 R5 R6 R7 |
The MegaCART has 4 hardware registers accessible as external RAM
starting at 080h. Although they are mirrored every 4 bytes I suggest to
only use the copies from 080h-083h, future hardware may have more
registers. The code bank switch method for code is based on the one used for
12K and 16K Videopac+ games. The data bank switch is similar to the one
used on Videopac 31 and 40, Musician
and 4 in 1 Row
.
All three read/write registers return the last value written to them when read.
ereg_codebankThis read/write register stores the current code bank. This sets the
address line A12-A19 for program code if P1.0 is 0. If P1.0 is set address
lines A12-A19 are all ones, so after reset bank 0ffh is active. The
ereg_codebank contains 0 after the BIOS routine
init is run. So it makes sense to first write 0ffh into
ereg_codebank and then clear P1.0 as part of an early
initialisation. In all banks the BIOS is still at 0-03ffh.
The way the code bank switch works is not compatible with the automatic
Videopac+ detection used by plusselectgame. If you use the
firmware you can check the iram_mode_plus bit, or check the BIOS
by a direct read like in the following example:
; detect videopac+
; The bank-switch of the MegaCART is not compatible with the usual
; way to detect VP+, so I check one of the two easily readable
; differences in the BIOS. (The other one is 0394h=0bbh for VP+)
section plusdetect
mov a,#07eh
movp3 a,@a ; read 037eh, 020h=std, 039h=VP+
xrl a,#039h
jz .ok
jmp normal ; no videopac+
.ok endsection plusdetect
ereg_databankThis read/write register stores the current data bank. This sets the
address line A12-A19 for data reads if P1.1 is 0. Additionally A8-A11 have
to be set by the lowest nibble of P2. Then the XROM read of the EPROM is
activated by a movx read. All the other read sources have to
be turned off: VDC, VPP and external RAM. Since the BIOS knows P1.1 only as
address line for its own bank switching, P1.1 has to be set manually before
using any other of the movx sources, the BIOS routines don't
do it.
This XROM read allows reading all bytes of the EPROM from any code location. It simplifies the handling of big data structures like Videopac+ data. The BIOS interrupt routines do not know about the XROM access, so you have to disable the interrupts while P1.1 is cleared.
Here are some macros I wrote to enable and disable XROM data read. More code can be found in my G7000 BIOS document. A full example program is on the demo program page.
; Enable XROM (read and write)
; P16=0 (enable cart signal), P11=0 (enable XROM), P15=1, P14=1, P13=1, P12=1
m_xromenable macro
orl P1,#03ch
anl P1,#0bdh
endm
; Disable XROM reading: P11=1
; This is needed because the BIOS extram/vdcenable routines don't touch P10/P11
m_xromdisable macro
orl P1,#002h
endm
; Switch from XROM to XRAM
m_xromtoram macro
orl P1,#0beh
anl P1,#0afh
endm
ereg_io_outThis read/write register is used to control some pins on the CPLD. Three of them are connected to the EEPROM, one is used on the FlashCART for communication. I strongly suggest that you insert the FlashCART firmware into your program if your want to use the EEPROM or talk to a PC.
| Bit 0 | eout_tx | This bit is used on the FlashCART as TX line. It is inverted, so that the BIOS initialises it to the correct level on the serial port. |
|---|---|---|
| Bit 1 | eout_eecs | This bit controls the chip select pin of the EEPROM. |
| Bit 2 | eout_eeclk | This bit controls the clock pin of the EEPROM. |
| Bit 3 | eout_eedi | This bit controls the data in pin of the EEPROM. |
All the eout_ definitions are bit masks,
not bit numbers.
ereg_io_inThis is a read only register which contains the level on some of the CPLD pins. Currently only one bit is used, the rest returns 0.
| Bit 0 | ein_eedo | This bit reads the data out pin of the EEPROM. |
|---|
The FlashCART has a 10 pin connector to allow future expansions. It has all the EEPROM signals on it, so you can leave the EEPROM on the FlashCART empty and plug in different EEPROMs for testing. It also has other signals that can be useful, one idea I have is to connect another SPI device besides the EEPROM which uses the TX signal for select. Or make the EEPROM outputs open-collector and use TWI/I2C peripherals.
| 5V | 1 | o | o | 2 | 3.3V |
| ROMSWITCH | 3 | o | o | 4 | TX |
| EEDO | 5 | o | o | 6 | EEDI |
| EECLK | 7 | o | o | 8 | EECS |
| GND | 9 | o | o | 10 | GND |
The first released version of the hardware is 1.1. For the rest the first released version is 1.0.
For a complete package you need the hardware, firmware and communication software.