Skip to content

Instantly share code, notes, and snippets.

@MarsTechHAN
Last active April 1, 2025 12:04
Show Gist options
  • Save MarsTechHAN/caf6bdf7b8356d9e55dd9aa929739b96 to your computer and use it in GitHub Desktop.
Save MarsTechHAN/caf6bdf7b8356d9e55dd9aa929739b96 to your computer and use it in GitHub Desktop.
Program Gowin from ESP32
import struct
import sys
if __name__ == '__main__':
fs = open(sys.argv[1], 'rb')
with open('fs.c', 'w+') as f:
print('const unsigned char fs_bitstream[] __attribute__((aligned(128))) ={', file=f)
counter = 0
while 1:
counter = counter + 1
fs_byte = fs.read(2)
if not fs_byte:
break
struct.unpack('>H', fs_byte)
print(', '.join([str(i) for i in fs_byte]) + ', ',end='', file=f)
if counter % 8 == 0:
print(file=f)
print(file=f)
print('};', file=f)
#include "fs.c" //fs_bitstream
#define TMS_SET digitalWrite(TMS_PIN, HIGH)
#define TMS_RESET digitalWrite(TMS_PIN, LOW)
#define TCK_SET digitalWrite(TCK_PIN, HIGH)
#define TCK_RESET digitalWrite(TCK_PIN, LOW)
#define TDI_SET digitalWrite(TDI_PIN, HIGH)
#define TDI_RESET digitalWrite(TDI_PIN, LOW)
#define TDO_VALUE digitalRead(TDO_PIN)
const uint8_t TCK_PIN = 22;
const uint8_t TDI_PIN = 19;
const uint8_t TDO_PIN = 23;
const uint8_t TMS_PIN = 33;
const uint8_t DELAY_LEN = 3;
const uint32_t BUFFER_SIZE = 0xff;
const uint32_t ID_GW1N9 = 0x1100581B;
typedef enum{
TAP_RESET,
TAP_IDLE,
TAP_DRSELECT,
TAP_DRCAPTURE,
TAP_DRSHIFT,
TAP_DREXIT1,
TAP_DRPAUSE,
TAP_DREXIT2,
TAP_DRUPDATE,
TAP_IRSELECT,
TAP_IRCAPTURE,
TAP_IRSHIFT,
TAP_IREXIT1,
TAP_IRPAUSE,
TAP_IREXIT2,
TAP_IRUPDATE,
TAP_UNKNOWN
} TAP_TypeDef;
typedef enum{
ISC_NOOP = 0x02,
ISC_ERASE = 0x05,
ERASE_DONE = 0x09,
READ_ID_CODE = 0x11,
ISC_ENABLE = 0x15,
FAST_PROGRAM = 0x17,
STATUS_CODE = 0x41,
JTAG_EF_PROGRAM = 0x71,
JTAG_EF_READ = 0x73,
JTAG_EF_ERASE = 0x75,
ISC_DISABLE = 0x3A,
REPROGRAM = 0x3C,
Bypass = 0xFF
} GWFPGA_Inst_Def;
typedef enum{
STATUS_CRC_ERROR = (1<<0),
STATUS_BAD_COMMAND = (1<<1),
STATUS_ID_VERIFY_FAILED = (1<<2),
STATUS_TIMEOUT = (1<<3),
STATUS_MEMORY_ERASE = (1<<5),
STATUS_PREAMBLE = (1<<6),
STATUS_SYSTEM_EDIT_MODE = (1<<7),
STATUS_PRG_SPIFLASH_DIRECT = (1<<8),
STATUS_NON_JTAG_CNF_ACTIVE = (1<<10),
STATUS_BYPASS = (1<<11),
STATUS_GOWIN_VLD = (1<<12),
STATUS_DONE_FINAL = (1<<13),
STATUS_SECURITY_FINAL = (1<<14),
STATUS_READY = (1<<15),
STATUS_POR = (1<<16),
STATUS_FLASH_LOCK = (1<<17)
} GWFPGA_StatusReg_Def;
void JTAG_Io_Init(){
pinMode(TCK_PIN, OUTPUT);
pinMode(TDI_PIN, OUTPUT);
pinMode(TMS_PIN, OUTPUT);
pinMode(TDO_PIN, INPUT);
}
void JTAG_TapMove_OneClock(uint8_t tms_value)
{
if(tms_value){
TMS_SET;
}else{
TMS_RESET;
}
TCK_RESET;
TCK_SET;
}
void JTAG_MoveTap(TAP_TypeDef TAP_From, TAP_TypeDef TAP_To)
{
if ((TAP_From == TAP_UNKNOWN) && (TAP_To==TAP_IDLE) )
{
JTAG_TapMove_OneClock(1);
JTAG_TapMove_OneClock(1);
JTAG_TapMove_OneClock(1);
JTAG_TapMove_OneClock(1);
JTAG_TapMove_OneClock(1);
JTAG_TapMove_OneClock(1);
JTAG_TapMove_OneClock(1);
JTAG_TapMove_OneClock(1);
JTAG_TapMove_OneClock(0);
JTAG_TapMove_OneClock(0);
}
else if ((TAP_From == TAP_IDLE) && (TAP_To==TAP_IDLE) )
{
JTAG_TapMove_OneClock(0);
JTAG_TapMove_OneClock(0);
JTAG_TapMove_OneClock(0);
}
else if ((TAP_From == TAP_IDLE) && (TAP_To==TAP_IRSHIFT) )
{
JTAG_TapMove_OneClock(1);
JTAG_TapMove_OneClock(1);
JTAG_TapMove_OneClock(0);
JTAG_TapMove_OneClock(0);
}
else if ((TAP_From == TAP_IDLE) && (TAP_To==TAP_DRSHIFT) )
{
JTAG_TapMove_OneClock(1);
JTAG_TapMove_OneClock(0);
JTAG_TapMove_OneClock(0);
}
else if ((TAP_From == TAP_IREXIT1) && (TAP_To==TAP_IDLE) )
{
JTAG_TapMove_OneClock(1);
JTAG_TapMove_OneClock(0);
JTAG_TapMove_OneClock(0);
}
else if ((TAP_From == TAP_DREXIT1) && (TAP_To==TAP_IDLE) )
{
JTAG_TapMove_OneClock(1);
JTAG_TapMove_OneClock(0);
JTAG_TapMove_OneClock(0);
}
else
{
Serial.printf("error tap walking.");
}
}
uint8_t JTAG_Write(uint8_t din, uint8_t dout, uint8_t tms, bool LSB)
{
uint8_t tmp = 0;
uint8_t dout_new = 0;
if (LSB==false)
{
uint8_t _tmp_din=0;
uint8_t sign = 1;
for (uint8_t i=0;i<=7;i++)
{
_tmp_din |=((din&(sign<<i))>>i)<<(7-i);
}
din = _tmp_din;
}
TMS_RESET;
for (uint8_t i=0; i<8; i++) // LSB
{
if (i == 7){
if((tms & 1) == 1)
TMS_SET;
}
tmp = din>>i ;
if((1&tmp) == 0)
TDI_RESET;
else
TDI_SET;
TCK_RESET;
TCK_SET;
dout_new <<= 1;
dout_new |= (TDO_VALUE & 1);
}
return dout_new;
}
void JTAG_WriteInst(uint8_t inst)
{
JTAG_MoveTap(TAP_IDLE, TAP_IRSHIFT);
JTAG_Write(inst, 0x0, 0x1,true);
JTAG_MoveTap(TAP_IREXIT1, TAP_IDLE);
JTAG_MoveTap(TAP_IDLE, TAP_IDLE);
JTAG_MoveTap(TAP_IDLE, TAP_IDLE);
JTAG_MoveTap(TAP_IDLE, TAP_IDLE);
}
void JTAG_RunTest(uint8_t cycles)
{
for (uint8_t i=0; i<cycles; i++)
{
JTAG_TapMove_OneClock(0);
}
}
uint32_t JTAG_ReadCode()
{
uint32_t out=0;
JTAG_WriteInst(READ_ID_CODE);
JTAG_MoveTap(TAP_IDLE, TAP_DRSHIFT);
TMS_RESET;
for (uint8_t i=0; i<32; i++)
{
if (i == 31) TMS_SET;
TCK_RESET;
TCK_SET;
out |= (TDO_VALUE) ? (1 << i) : 0;
};
JTAG_MoveTap(TAP_DREXIT1, TAP_IDLE);
return out;
}
uint32_t JTAG_ReadStatus()
{
uint32_t out=0;
JTAG_WriteInst(STATUS_CODE);
JTAG_MoveTap(TAP_IDLE, TAP_DRSHIFT);
TMS_RESET;
for (uint8_t i=0; i<32; i++)
{
if (i == 31) TMS_SET;
TCK_RESET;
TCK_SET;
out |= (TDO_VALUE) ? (1 << i) : 0;
};
JTAG_MoveTap(TAP_DREXIT1, TAP_IDLE);
return out;
}
void displayReadReg(uint32_t dev)
{
Serial.printf("STATUS_REG: %08x\n", dev);
if (dev & STATUS_CRC_ERROR)
Serial.printf("\tCRC Error\n");
if (dev & STATUS_BAD_COMMAND)
Serial.printf("\tBad Command\n");
if (dev & STATUS_ID_VERIFY_FAILED)
Serial.printf("\tID Verify Failed\n");
if (dev & STATUS_TIMEOUT)
Serial.printf("\tTimeout\n");
if (dev & STATUS_MEMORY_ERASE)
Serial.printf("\tMemory Erase\n");
if (dev & STATUS_PREAMBLE)
Serial.printf("\tPreamble\n");
if (dev & STATUS_SYSTEM_EDIT_MODE)
Serial.printf("\tSystem Edit Mode\n");
if (dev & STATUS_PRG_SPIFLASH_DIRECT)
Serial.printf("\tProgram spi flash directly\n");
if (dev & STATUS_NON_JTAG_CNF_ACTIVE)
Serial.printf("\tNon-jtag is active\n");
if (dev & STATUS_BYPASS)
Serial.printf("\tBypass\n");
if (dev & STATUS_GOWIN_VLD)
Serial.printf("\tGowin VLD\n");
if (dev & STATUS_DONE_FINAL)
Serial.printf("\tDone Final\n");
if (dev & STATUS_SECURITY_FINAL)
Serial.printf("\tSecurity Final\n");
if (dev & STATUS_READY)
Serial.printf("\tReady\n");
if (dev & STATUS_POR)
Serial.printf("\tPOR\n");
if (dev & STATUS_FLASH_LOCK)
Serial.printf("\tFlash Lock\n");
}
void setup() {
Serial.begin(115200);
Serial.println("Starting JTAG Chain...");
uint32_t debug_timming = millis();
JTAG_Io_Init();
Serial.println("---------------------------");
Serial.println("Reading IDCODE...");
uint32_t ID_CODE = JTAG_ReadCode();
Serial.printf("IDCODE: 0x%X\n", ID_CODE);
Serial.println("---------------------------");
Serial.println("Reading Status Reg...");
uint32_t STATUS_REG = JTAG_ReadStatus();
displayReadReg(STATUS_REG);
Serial.println("---------------------------");
Serial.println("Starting Writing to SRAM...");
JTAG_WriteInst(ISC_ENABLE);
JTAG_WriteInst(ISC_ERASE);
JTAG_WriteInst(ISC_NOOP);
uint32_t erase_time = millis();
while(millis() - erase_time < 4){ //TN653
TCK_RESET;
TCK_SET;
}
JTAG_WriteInst(ERASE_DONE);
JTAG_WriteInst(ISC_NOOP);
JTAG_WriteInst(ISC_DISABLE);
JTAG_WriteInst(ISC_NOOP);
erase_time = millis();
while(millis() - erase_time < 4){
TCK_RESET;
TCK_SET;
}
JTAG_WriteInst(ISC_ENABLE);
JTAG_WriteInst(FAST_PROGRAM);
JTAG_MoveTap(TAP_IDLE, TAP_DRSHIFT);
uint8_t tx_end = 0;
for (uint32_t i=0; i < sizeof(fs_bitstream); i+=1) {
if (i == sizeof(fs_bitstream) - 1)
tx_end = 1; // to move in EXIT1_DR
JTAG_Write(fs_bitstream[i], 0x00, tx_end, 0x00);
}
JTAG_MoveTap(TAP_DREXIT1, TAP_IDLE);
JTAG_WriteInst(ISC_DISABLE);
JTAG_WriteInst(ISC_NOOP);
Serial.println("SRAM Prog Finish...");
Serial.println("---------------------------");
Serial.println("Waiting for DONE...");
while(!(JTAG_ReadStatus() & STATUS_DONE_FINAL))
delay(1);
Serial.println("Done!");
Serial.println("---------------------------");
Serial.printf("Total Time: %ums", (millis() - debug_timming));
}
void loop() {
}
#From @ciniml https://gist.github.com/ciniml/e02f4cc9b00f30d950cd2a787a1ea8d3
import sys
input_path = sys.argv[1]
output_path = sys.argv[1].replace('.fs', '.bin')
with open(input_path, 'r') as input_file:
with open(output_path, 'wb') as output_file:
for line in iter(input_file.readline, ''): #type: str
line = line.strip()
if line.startswith('//'):
continue
buffer = bytearray(1)
for byte_index in range(0, len(line), 8):
value = 0
for bit_index in range(8):
bit = line[byte_index + bit_index]
value = (value << 1) | (1 if bit == '1' else 0)
buffer[0] = value
output_file.write(buffer)
@apuder
Copy link

apuder commented Nov 9, 2024

I have done something similar for one of my projects: https://github.com/apuder/TRS-IO/blob/master/src/esp/components/jtag/jtag.cpp
I am having trouble programming via SRAM when the content of the external flash (I am using a 20K) is corrupt. The status register shows a CRC, but unfortunately it also prevents the programming via SRAM to work. Have you run into the same issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment