b-dmitry1 / BIOS

Very compact (8KB) embedded x86 BIOS for FPGA/emulators/386EX
16 stars 3 forks source link

Question about ROM programming? Supports add-on ROM chips (see config.inc) #1

Open bConfig opened 2 years ago

bConfig commented 2 years ago

Hello, I am trying to get some insights from your code's ROM interface. I want to emulate a ROM programmer using FPGA and I want to program the 6-pi EEPROM BIOS rom chip of a computer for example.

I would really appreciate if you could give me some insights on how I should approach this problem(and moreover, is it doable)?

What I want to do is have my FPGA be the functional block between USB interface and the 6-pin EEPROM interface. And make it do the function of this device: (known as EEPROM programmers such as EZP2023... and some other variants) https://www.aliexpress.com/item/1005003520543743.html

Is this possible?

The chip I want to program with a custom ROM.bin file is this : https://www.winbond.com/productResource-files/Winbond_Serial_Flash_Product%20Brief.pdf

And I want to use a Spartan 3E Xilinx BASYS-2 board : https://digilent.com/reference/programmable-logic/basys-2/start

b-dmitry1 commented 2 years ago

Hello. I like this EEPROM chips. They are inexpensive, reliable, and have a very simple data protocol.

The simplest programmer's algorithm may look like this:

  1. Notify your data provider (for example, by sending "ready" status via USB) that you are ready to perform write.
  2. Receive 3 address bytes (higher goes first) and 4096 bytes of data from USB's endpoint to a FPGA's RAM block.
  3. Issue a "Write enable" command by setting CS pin low sending 0x06 byte to a flash, and setting CS pin high.
  4. Issue an "Erase block" command by setting CS pin low, sending 0x20 byte, sending 3 address bytes (higher first) to a flash, and setting CS pin high.
  5. Wait for the erase to be completed by reading status register by setting CS pin low, sending 0x05 byte, reading one byte by sending 0xFF byte, and setting CS pin high. If bit 0 of the received byte is 1 then repeat reading status until it becomes 0.
  6. Issue a "Write enable" command again like shown in a step 3.
  7. Issue an "Write sector" command by setting CS pin low, sending 0x02 byte, sending 3 address bytes (higher first) to a flash, sending 256 bytes of data to a flash, and setting CS pin high.
  8. Wait for writing to be completed by reading status register like shown in a step 5.
  9. Repeat steps 6-8 until all 4096 bytes will be written.

I think this will be a good start.

The algorithm can be converted to a finite state machine inside FPGA, and should take ~500 LEs + 4 kbyte RAM block.

Hope you have a ready-to-use USB device core and a driver for your FPGA. If not, maybe a low-speed HID device protocol with 1 control and 1 data endpoint will be enough to begin. HID devices doesn't require a driver and have a lots of programming examples over the Internet. The easiest choice is an external USB-to-UART converter running at a high speed. I prefer CH340C chips if I need USB because they requires only 3 small capacitors.

Please note that we can erase 4096 bytes at a time (or a whole flash if you want to, this may take ~20 seconds), but write only 256 bytes (sector) at a time. So to program an erased page you'll have to repeat a 256-byte sector write 16 times. 6-wire (4x speed) fast mode is harder to implement than 4-wire SPI mode, so I recommend not to use it until 4-wire mode work perfectly.

I double-checked the command sequences but it will be a good idea to try this finite state machine on a microcontroller before trying to implement it on FPGA. A smallest STM32 or even an Arduino board could save many hours of debugging the code.

There are simple UART and SPI cores in my V188 project. They aren't so good, but I think they may be applicable to your project.

As an alternative to a finite state machine you can use a soft CPU with SPI port (CPU like a soft Z80 (~2300 LEs)). This will be a good idea if you want to allow your customers to upgrade the programmer's firmware.