Прошивка моста BL616 для Tang Primer 25K и программатор TangProgrammer
- src/: прошивка встроенного отладчика BL616 — составное USB-устройство 1209:C0CA: DirtyJTAG v3 (WinUSB через MS OS 2.0) + CDC-ACM UART к FPGA B3/C3; UART до 20 Мбод на DMA, JTAG до 30 МГц через аппаратный SPI; - bin/: загрузчик Sipeed (0x0) и штатная прошивка 2025030317 для отката; - gui/: TangProgrammer.exe (C# WinForms, .NET Framework 4) — загрузка FPGA в SRAM и во флеш-память, копия и стирание флеш-памяти FPGA, прошивка моста; светлая и тёмная тема; - scripts/: setup, build, flash, build_gui, make_portable, а также make_release и publish_release для релизов Gitea; - fpga_test/, tests/: тестовые проекты Gowin (loopback, stream) и тесты UART на Python; - tools/openFPGALoader/: openFPGALoader 1.1.1 для Windows x64.
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
# Build the firmware: build\build_out\tang25k_debugger_bl616.bin
|
||||
param([switch]$Clean)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
. (Join-Path $PSScriptRoot 'common.ps1')
|
||||
|
||||
$root = Get-ProjectRoot
|
||||
Set-BuildEnv $root
|
||||
Push-Location $root
|
||||
try {
|
||||
if ($Clean) {
|
||||
Remove-Item -Recurse -Force build -ErrorAction SilentlyContinue
|
||||
}
|
||||
& make.exe CHIP=bl616 BOARD=bl616dk
|
||||
if ($LASTEXITCODE) { throw "build failed ($LASTEXITCODE)" }
|
||||
$bin = Get-Item build\build_out\tang25k_debugger_bl616.bin
|
||||
Write-Host ("OK: {0} ({1} bytes)" -f $bin.FullName, $bin.Length) -ForegroundColor Green
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
# Build TangProgrammer.exe (the GUI for openFPGALoader and the bridge firmware)
|
||||
# with the C# compiler that comes with Windows (.NET Framework 4.x): nothing
|
||||
# has to be installed.
|
||||
#
|
||||
# .\scripts\build_gui.ps1 -> TangProgrammer.exe in the project root
|
||||
# .\scripts\build_gui.ps1 -Out some.exe -> elsewhere
|
||||
param([string]$Out)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$root = Split-Path $PSScriptRoot -Parent
|
||||
$src = Join-Path $root 'gui'
|
||||
if (-not $Out) { $Out = Join-Path $root 'TangProgrammer.exe' }
|
||||
$csc = Join-Path $env:WINDIR 'Microsoft.NET\Framework64\v4.0.30319\csc.exe'
|
||||
if (-not (Test-Path $csc)) {
|
||||
$csc = Join-Path $env:WINDIR 'Microsoft.NET\Framework\v4.0.30319\csc.exe'
|
||||
}
|
||||
if (-not (Test-Path $csc)) { throw '.NET Framework 4 C# compiler (csc.exe) not found' }
|
||||
|
||||
$sources = Get-ChildItem (Join-Path $src '*.cs') | ForEach-Object { $_.FullName }
|
||||
& $csc /nologo /target:winexe /optimize+ /codepage:65001 "/out:$Out" `
|
||||
"/win32icon:$src\app.ico" "/win32manifest:$src\app.manifest" "/resource:$src\app.ico,TangProgrammer.app.ico" `
|
||||
/r:System.dll /r:System.Drawing.dll /r:System.Windows.Forms.dll /r:System.Management.dll `
|
||||
$sources
|
||||
if ($LASTEXITCODE) { throw "csc failed ($LASTEXITCODE) - is $Out running?" }
|
||||
Write-Host "OK: $Out" -ForegroundColor Green
|
||||
@@ -0,0 +1,42 @@
|
||||
# Shared helpers for build/flash scripts.
|
||||
|
||||
# A mapped drive that points back to a share on this very PC (D: -> \\THISPC\Projects)
|
||||
# makes every compiler launch go through SMB and antivirus scanning: builds
|
||||
# get ~50x slower. Translate such paths to the local folder behind the share.
|
||||
function Resolve-LocalPath([string]$Path) {
|
||||
$full = (Resolve-Path $Path).ProviderPath
|
||||
$drive = Get-PSDrive -Name $full.Substring(0, 1) -ErrorAction SilentlyContinue
|
||||
if ($drive -and $drive.DisplayRoot -match '^\\\\([^\\]+)\\([^\\]+)') {
|
||||
if ($Matches[1] -ieq $env:COMPUTERNAME) {
|
||||
$share = Get-CimInstance Win32_Share -Filter "Name='$($Matches[2])'" -ErrorAction SilentlyContinue
|
||||
if ($share) {
|
||||
return Join-Path $share.Path $full.Substring(3)
|
||||
}
|
||||
}
|
||||
}
|
||||
return $full
|
||||
}
|
||||
|
||||
function Get-ProjectRoot {
|
||||
return Resolve-LocalPath (Join-Path $PSScriptRoot '..')
|
||||
}
|
||||
|
||||
function Set-BuildEnv([string]$Root) {
|
||||
$sdk = Join-Path $Root 'third_party\bouffalo_sdk'
|
||||
$tc = Join-Path $Root 'third_party\toolchain_gcc_t-head_windows\bin'
|
||||
if (-not (Test-Path $sdk) -or -not (Test-Path $tc)) {
|
||||
throw "SDK/toolchain not found in $Root\third_party - run scripts\setup.ps1 first"
|
||||
}
|
||||
$env:BL_SDK_BASE = $sdk
|
||||
$env:PATH = "$tc;$sdk\tools\make;$sdk\tools\ninja;$sdk\tools\cmake\bin;$env:SystemRoot\System32;$env:SystemRoot"
|
||||
}
|
||||
|
||||
# COM port name(s) of present devices whose instance id matches the pattern
|
||||
function Find-ComPort([string]$IdPattern) {
|
||||
Get-CimInstance Win32_PnPEntity -Filter "PNPClass='Ports'" -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.PNPDeviceID -match $IdPattern -and $_.Name -match '\((COM\d+)\)' } |
|
||||
ForEach-Object { [regex]::Match($_.Name, '\((COM\d+)\)').Groups[1].Value }
|
||||
}
|
||||
|
||||
$BootromPortId = 'VID_349B&PID_6160' # BL616 ROM USB bootloader "Bouffalo CDC DEMO"
|
||||
$FirmwarePortId = 'VID_1209&PID_C0CA&MI_01' # this firmware's CDC UART
|
||||
@@ -0,0 +1,72 @@
|
||||
# Flash the BL616 on the Tang Primer 25K Dock.
|
||||
#
|
||||
# .\scripts\flash.ps1 this firmware (Sipeed loader @0x0 + firmware @0x20000)
|
||||
# .\scripts\flash.ps1 -Restore original Sipeed debugger firmware
|
||||
#
|
||||
# The BL616 has to be in its ROM USB bootloader ("Bouffalo CDC DEMO"). The
|
||||
# script gets it there by itself when this firmware is already running
|
||||
# (serial port opened at 1234 baud). Otherwise, unplug the board and plug it
|
||||
# back while either
|
||||
# - holding the S3 button (this firmware is installed), or
|
||||
# - shorting the TDO test point to 3V3 (bottom side, always works).
|
||||
param(
|
||||
[switch]$Restore,
|
||||
[string]$Port
|
||||
)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
. (Join-Path $PSScriptRoot 'common.ps1')
|
||||
|
||||
$root = Get-ProjectRoot
|
||||
$sdk = Join-Path $root 'third_party\bouffalo_sdk'
|
||||
$tool = Join-Path $sdk 'tools\bflb_tools\bouffalo_flash_cube\BLFlashCommand.exe'
|
||||
$cfg = if ($Restore) { 'restore_prog_cfg.ini' } else { 'flash_prog_cfg.ini' }
|
||||
|
||||
if (-not $Restore -and -not (Test-Path (Join-Path $root 'build\build_out\tang25k_debugger_bl616.bin'))) {
|
||||
throw 'firmware not built yet: run scripts\build.ps1'
|
||||
}
|
||||
|
||||
function Wait-BootromPort([int]$Seconds) {
|
||||
$deadline = (Get-Date).AddSeconds($Seconds)
|
||||
do {
|
||||
$p = @(Find-ComPort $BootromPortId)
|
||||
if ($p.Count) { return $p[0] }
|
||||
Start-Sleep -Milliseconds 300
|
||||
} while ((Get-Date) -lt $deadline)
|
||||
return $null
|
||||
}
|
||||
|
||||
if (-not $Port) {
|
||||
$Port = @(Find-ComPort $BootromPortId) | Select-Object -First 1
|
||||
}
|
||||
if (-not $Port) {
|
||||
$fw = @(Find-ComPort $FirmwarePortId) | Select-Object -First 1
|
||||
if ($fw) {
|
||||
Write-Host "Firmware found on $fw, rebooting it into the ROM bootloader..."
|
||||
try {
|
||||
$sp = New-Object System.IO.Ports.SerialPort $fw, 1234
|
||||
$sp.Open()
|
||||
Start-Sleep -Milliseconds 200
|
||||
$sp.Close()
|
||||
} catch {
|
||||
Write-Warning "could not open ${fw}: $_ (is a terminal using it?)"
|
||||
}
|
||||
$Port = Wait-BootromPort 15
|
||||
}
|
||||
}
|
||||
if (-not $Port) {
|
||||
Write-Host 'Waiting for the BL616 ROM bootloader (Bouffalo CDC DEMO)...' -ForegroundColor Yellow
|
||||
Write-Host ' unplug the board, then plug it back while holding S3'
|
||||
Write-Host ' (or while shorting the TDO test point to 3V3 on the bottom side)'
|
||||
$Port = Wait-BootromPort 120
|
||||
}
|
||||
if (-not $Port) { throw 'BL616 bootloader port not found' }
|
||||
|
||||
Write-Host "Flashing $cfg via $Port" -ForegroundColor Cyan
|
||||
Push-Location $root
|
||||
try {
|
||||
& $tool --interface=uart --baudrate=2000000 --port=$Port --chipname=bl616 --cpu_id= --config=$cfg
|
||||
if ($LASTEXITCODE) { throw "BLFlashCommand failed ($LASTEXITCODE)" }
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
Write-Host 'Done. Unplug and plug the board back (power cycle) to start the new firmware.' -ForegroundColor Green
|
||||
@@ -0,0 +1,80 @@
|
||||
# Make a portable copy of TangProgrammer for another PC: the program and only
|
||||
# the tools it runs (no SDK, no toolchain, no sources).
|
||||
#
|
||||
# .\scripts\make_portable.ps1 -> dist\TangProgrammer\ and dist\TangProgrammer.zip
|
||||
#
|
||||
# The FPGA and FPGA-flash tabs need TangProgrammer.exe + tools\openFPGALoader.
|
||||
# The bridge firmware tab also needs BLFlashCommand (for flashing over the USB
|
||||
# bootloader only the exe and chips\ are used, not the 200+ MB of debug probe
|
||||
# tools around it), the firmware images and the flash configs.
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$root = Split-Path $PSScriptRoot -Parent
|
||||
$dist = Join-Path $root 'dist'
|
||||
$out = Join-Path $dist 'TangProgrammer'
|
||||
$cube = Join-Path $root 'third_party\bouffalo_sdk\tools\bflb_tools\bouffalo_flash_cube'
|
||||
$bridgeFw = Join-Path $root 'build\build_out\tang25k_debugger_bl616.bin'
|
||||
|
||||
if (Test-Path $out) { Remove-Item -Recurse -Force $out }
|
||||
New-Item -ItemType Directory -Force (Join-Path $out 'tools') | Out-Null
|
||||
|
||||
& (Join-Path $PSScriptRoot 'build_gui.ps1') -Out (Join-Path $out 'TangProgrammer.exe')
|
||||
Copy-Item -Recurse (Join-Path $root 'tools\openFPGALoader') (Join-Path $out 'tools\openFPGALoader')
|
||||
|
||||
if (Test-Path (Join-Path $cube 'BLFlashCommand.exe')) {
|
||||
$dst = Join-Path $out 'tools\bouffalo_flash_cube'
|
||||
New-Item -ItemType Directory -Force $dst | Out-Null
|
||||
Copy-Item (Join-Path $cube 'BLFlashCommand.exe') $dst
|
||||
Copy-Item -Recurse (Join-Path $cube 'chips') $dst
|
||||
} else {
|
||||
Write-Warning 'Bouffalo SDK is not installed (scripts\setup.ps1): the bridge firmware tab will not work in the copy'
|
||||
}
|
||||
|
||||
$fwDir = Join-Path $out 'firmware'
|
||||
New-Item -ItemType Directory -Force $fwDir | Out-Null
|
||||
Copy-Item (Join-Path $root 'bin\bl616_bootloader_0x20000_nano20k_signed.bin') $fwDir
|
||||
Copy-Item (Join-Path $root 'bin\bl616_fpga_partner_25kDock.bin') $fwDir
|
||||
if (Test-Path $bridgeFw) {
|
||||
Copy-Item $bridgeFw $fwDir
|
||||
} else {
|
||||
Write-Warning 'bridge firmware is not built (scripts\build.ps1): it is missing from the copy'
|
||||
}
|
||||
|
||||
# the same configs as in the project root, pointing at firmware\
|
||||
Set-Content -Encoding ASCII (Join-Path $out 'flash_prog_cfg.ini') @'
|
||||
[cfg]
|
||||
# 0: no erase, 1: programmed section erase, 2: chip erase
|
||||
erase = 1
|
||||
skip_mode = 0x0, 0x0
|
||||
boot2_isp_mode = 0
|
||||
|
||||
# Sipeed-encrypted stage-1 loader: the eFuse secure boot only runs images
|
||||
# encrypted with Sipeed's key at 0x0. It unconditionally jumps to 0x20000.
|
||||
[bootloader]
|
||||
filedir = ./firmware/bl616_bootloader_0x20000_nano20k_signed.bin
|
||||
address = 0x0
|
||||
|
||||
[FW]
|
||||
filedir = ./firmware/tang25k_debugger_bl616.bin
|
||||
address = 0x20000
|
||||
'@
|
||||
Set-Content -Encoding ASCII (Join-Path $out 'restore_prog_cfg.ini') @'
|
||||
[cfg]
|
||||
# 0: no erase, 1: programmed section erase, 2: chip erase
|
||||
erase = 1
|
||||
skip_mode = 0x0, 0x0
|
||||
boot2_isp_mode = 0
|
||||
|
||||
# Original Sipeed debugger firmware (FT2232 emulation), version 2025030317
|
||||
[FW]
|
||||
filedir = ./firmware/bl616_fpga_partner_25kDock.bin
|
||||
address = 0x0
|
||||
'@
|
||||
|
||||
Copy-Item (Join-Path $root 'gui\portable_readme.txt') (Join-Path $out 'README.txt')
|
||||
|
||||
$zip = Join-Path $dist 'TangProgrammer.zip'
|
||||
if (Test-Path $zip) { Remove-Item -Force $zip }
|
||||
Compress-Archive -Path $out -DestinationPath $zip
|
||||
$size = (Get-ChildItem -Recurse $out | Measure-Object -Sum Length).Sum
|
||||
Write-Host ("OK: {0} ({1:N1} MB), {2} ({3:N1} MB)" -f $out, ($size / 1MB), $zip, ((Get-Item $zip).Length / 1MB)) -ForegroundColor Green
|
||||
@@ -0,0 +1,56 @@
|
||||
# Collect the files of a release into dist\release\v<version>\:
|
||||
#
|
||||
# TangProgrammer-v<version>-win64.zip portable programmer (make_portable.ps1)
|
||||
# TangProgrammer.exe the program alone
|
||||
# tang25k_debugger_bl616.bin bridge firmware, @0x20000
|
||||
# bl616_bootloader_0x20000_nano20k_signed.bin Sipeed loader, @0x0
|
||||
# bl616_fpga_partner_25kDock.bin original Sipeed firmware, @0x0
|
||||
# fpga_test_bitstreams-GW5A-25.zip fpga_test\*\impl\pnr\*.fs, if built
|
||||
# SHA256SUMS.txt
|
||||
#
|
||||
# .\scripts\build.ps1
|
||||
# .\scripts\make_release.ps1 version from FW_VERSION_STR in src\sys.h
|
||||
param([string]$Version)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$root = Split-Path $PSScriptRoot -Parent
|
||||
if (-not $Version) {
|
||||
$m = Select-String -Path (Join-Path $root 'src\sys.h') -Pattern '#define\s+FW_VERSION_STR\s+"([^"]+)"'
|
||||
if (-not $m) { throw 'FW_VERSION_STR not found in src\sys.h' }
|
||||
$Version = $m.Matches[0].Groups[1].Value
|
||||
}
|
||||
$tag = 'v' + $Version.TrimStart('v')
|
||||
|
||||
$bridgeFw = Join-Path $root 'build\build_out\tang25k_debugger_bl616.bin'
|
||||
if (-not (Test-Path $bridgeFw)) { throw 'bridge firmware is not built: run scripts\build.ps1' }
|
||||
if (-not (Test-Path (Join-Path $root 'third_party\bouffalo_sdk\tools\bflb_tools\bouffalo_flash_cube\BLFlashCommand.exe'))) {
|
||||
throw 'Bouffalo SDK is not installed (scripts\setup.ps1): the portable copy needs BLFlashCommand'
|
||||
}
|
||||
|
||||
$out = Join-Path $root "dist\release\$tag"
|
||||
if (Test-Path $out) { Remove-Item -Recurse -Force $out }
|
||||
New-Item -ItemType Directory -Force $out | Out-Null
|
||||
|
||||
& (Join-Path $PSScriptRoot 'make_portable.ps1')
|
||||
Copy-Item (Join-Path $root 'dist\TangProgrammer.zip') (Join-Path $out "TangProgrammer-$tag-win64.zip")
|
||||
Copy-Item (Join-Path $root 'dist\TangProgrammer\TangProgrammer.exe') $out
|
||||
|
||||
Copy-Item $bridgeFw $out
|
||||
Copy-Item (Join-Path $root 'bin\bl616_bootloader_0x20000_nano20k_signed.bin') $out
|
||||
Copy-Item (Join-Path $root 'bin\bl616_fpga_partner_25kDock.bin') $out
|
||||
|
||||
$fs = @(Get-ChildItem (Join-Path $root 'fpga_test\*\impl\pnr\*.fs') -ErrorAction SilentlyContinue)
|
||||
if ($fs.Count) {
|
||||
Compress-Archive -Path ($fs | ForEach-Object { $_.FullName }) -DestinationPath (Join-Path $out 'fpga_test_bitstreams-GW5A-25.zip')
|
||||
} else {
|
||||
Write-Warning 'no test bitstreams: build them with gw_sh build.tcl in fpga_test\loopback and fpga_test\stream'
|
||||
}
|
||||
|
||||
# sha256sum format, so that "sha256sum -c SHA256SUMS.txt" works
|
||||
$sums = Get-ChildItem $out -File | Sort-Object Name | ForEach-Object {
|
||||
(Get-FileHash -Algorithm SHA256 $_.FullName).Hash.ToLower() + ' ' + $_.Name
|
||||
}
|
||||
[IO.File]::WriteAllText((Join-Path $out 'SHA256SUMS.txt'), ($sums -join "`n") + "`n")
|
||||
|
||||
Get-ChildItem $out -File | Sort-Object Name | Format-Table Name, @{ n = 'KB'; e = { [math]::Ceiling($_.Length / 1KB) }; a = 'right' } -AutoSize
|
||||
Write-Host "OK: $out" -ForegroundColor Green
|
||||
@@ -0,0 +1,91 @@
|
||||
# Publish dist\release\v<version>\ (made by make_release.ps1) as a Gitea
|
||||
# release: the release text is the version's section of CHANGELOG.md. The tag
|
||||
# has to be pushed already. Re-running uploads only the files that are missing.
|
||||
#
|
||||
# Needs a Gitea access token with the write:repository scope
|
||||
# (Settings -> Applications -> Generate New Token):
|
||||
#
|
||||
# $env:GITEA_TOKEN = '<token>'
|
||||
# .\scripts\publish_release.ps1 version from src\sys.h
|
||||
# .\scripts\publish_release.ps1 -Version 1.0.1
|
||||
param(
|
||||
[string]$Version,
|
||||
[string]$Token = $env:GITEA_TOKEN,
|
||||
[string]$Remote = 'origin'
|
||||
)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$root = Split-Path $PSScriptRoot -Parent
|
||||
if (-not $Version) {
|
||||
$m = Select-String -Path (Join-Path $root 'src\sys.h') -Pattern '#define\s+FW_VERSION_STR\s+"([^"]+)"'
|
||||
if (-not $m) { throw 'FW_VERSION_STR not found in src\sys.h' }
|
||||
$Version = $m.Matches[0].Groups[1].Value
|
||||
}
|
||||
$Version = $Version.TrimStart('v')
|
||||
$tag = 'v' + $Version
|
||||
$dir = Join-Path $root "dist\release\$tag"
|
||||
if (-not (Test-Path $dir)) { throw "$dir not found: run scripts\make_release.ps1 first" }
|
||||
if (-not $Token) { throw 'no token: set $env:GITEA_TOKEN (Gitea: Settings -> Applications -> Generate New Token, scope write:repository)' }
|
||||
|
||||
# http://server/owner/repo.git -> http://server/api/v1/repos/owner/repo
|
||||
$url = (& git -C $root remote get-url $Remote).Trim()
|
||||
if ($url -notmatch '^(https?://[^/]+)/(.+?)(\.git)?/?$') { throw "not an http(s) remote: $url" }
|
||||
$api = "$($Matches[1])/api/v1/repos/$($Matches[2])"
|
||||
|
||||
# the release text: the lines under "## v<version>" up to the next "## "
|
||||
$notes = New-Object System.Collections.Generic.List[string]
|
||||
$inside = $false
|
||||
foreach ($line in [IO.File]::ReadAllLines((Join-Path $root 'CHANGELOG.md'), [Text.Encoding]::UTF8)) {
|
||||
if ($line -match '^## ') {
|
||||
if ($inside) { break }
|
||||
$inside = $line -match "^## v?$([regex]::Escape($Version))\b"
|
||||
} elseif ($inside) {
|
||||
$notes.Add($line)
|
||||
}
|
||||
}
|
||||
if (-not $inside) { throw "no '## $tag' section in CHANGELOG.md" }
|
||||
$body = ($notes -join "`n").Trim()
|
||||
|
||||
Add-Type -AssemblyName System.Net.Http
|
||||
$http = New-Object System.Net.Http.HttpClient
|
||||
$http.Timeout = [TimeSpan]::FromMinutes(10)
|
||||
$http.DefaultRequestHeaders.Authorization = New-Object System.Net.Http.Headers.AuthenticationHeaderValue 'token', $Token
|
||||
|
||||
function Invoke-Gitea([string]$Method, [string]$Path, [System.Net.Http.HttpContent]$Content) {
|
||||
$req = New-Object System.Net.Http.HttpRequestMessage ([System.Net.Http.HttpMethod]::new($Method)), ($api + $Path)
|
||||
if ($Content) { $req.Content = $Content }
|
||||
$resp = $http.SendAsync($req).GetAwaiter().GetResult()
|
||||
$text = $resp.Content.ReadAsStringAsync().GetAwaiter().GetResult()
|
||||
$code = [int]$resp.StatusCode
|
||||
if ($code -ge 400 -and $code -ne 404) { throw "$Method $Path -> $code $text" }
|
||||
return [pscustomobject]@{ Code = $code; Json = $(if ($text) { $text | ConvertFrom-Json } else { $null }) }
|
||||
}
|
||||
|
||||
if ((Invoke-Gitea GET "/tags/$tag").Code -eq 404) {
|
||||
throw "tag $tag is not on the server: git tag -a $tag -m $tag; git push $Remote $tag"
|
||||
}
|
||||
|
||||
$r = Invoke-Gitea GET "/releases/tags/$tag"
|
||||
if ($r.Code -eq 404) {
|
||||
$json = ConvertTo-Json @{ tag_name = $tag; name = $tag; body = $body; draft = $false; prerelease = $false }
|
||||
$r = Invoke-Gitea POST '/releases' (New-Object System.Net.Http.StringContent $json, ([Text.Encoding]::UTF8), 'application/json')
|
||||
Write-Host "Created release $tag"
|
||||
} else {
|
||||
Write-Host "Release $tag exists, adding missing files"
|
||||
}
|
||||
$release = $r.Json
|
||||
$have = @($release.assets | ForEach-Object { $_.name })
|
||||
|
||||
foreach ($f in Get-ChildItem $dir -File | Sort-Object Name) {
|
||||
if ($have -contains $f.Name) {
|
||||
Write-Host " = $($f.Name) (already there)"
|
||||
continue
|
||||
}
|
||||
$file = [System.Net.Http.ByteArrayContent]::new([IO.File]::ReadAllBytes($f.FullName))
|
||||
$file.Headers.ContentType = [System.Net.Http.Headers.MediaTypeHeaderValue]::new('application/octet-stream')
|
||||
$form = New-Object System.Net.Http.MultipartFormDataContent
|
||||
$form.Add($file, 'attachment', $f.Name)
|
||||
Invoke-Gitea POST "/releases/$($release.id)/assets?name=$([Uri]::EscapeDataString($f.Name))" $form | Out-Null
|
||||
Write-Host (" + {0} ({1:N0} KB)" -f $f.Name, ($f.Length / 1KB))
|
||||
}
|
||||
Write-Host "OK: $($release.html_url)" -ForegroundColor Green
|
||||
@@ -0,0 +1,15 @@
|
||||
# Fetch the Bouffalo SDK and the T-Head RISC-V toolchain into third_party\.
|
||||
$ErrorActionPreference = 'Stop'
|
||||
. (Join-Path $PSScriptRoot 'common.ps1')
|
||||
|
||||
$root = Get-ProjectRoot
|
||||
$tp = Join-Path $root 'third_party'
|
||||
New-Item -ItemType Directory -Force $tp | Out-Null
|
||||
|
||||
if (-not (Test-Path (Join-Path $tp 'bouffalo_sdk'))) {
|
||||
git clone --depth 1 --branch v2.3.16 https://github.com/bouffalolab/bouffalo_sdk.git (Join-Path $tp 'bouffalo_sdk')
|
||||
}
|
||||
if (-not (Test-Path (Join-Path $tp 'toolchain_gcc_t-head_windows'))) {
|
||||
git clone --depth 1 https://github.com/bouffalolab/toolchain_gcc_t-head_windows.git (Join-Path $tp 'toolchain_gcc_t-head_windows')
|
||||
}
|
||||
Write-Host 'SDK and toolchain are in place.' -ForegroundColor Green
|
||||
Reference in New Issue
Block a user