; --------------------------------------------------------------------------------
; @Title: Load the FPGA of a CycloneV SoC using the FPGA Manager
; @Description:
;   This script loads a RBF file generated by the Altera Toolchain into the FPGA
;   using the FPGA Manager peripheral.
;   Prerequisites:
;     * Matching RBF file for the FPGA is available
;     * DRAM is available and accessible as ReadWrite
;     * Debug session is in SYStem.UP() state
;     * set MIO to FPPx16 or FPPx32 mode
;   Usage:
;     DO cyclonevsoc_fpgaloadrbf.cmm "<PathTo>/<filename>.rbf" <DRamAddress>
;     DO cyclonevsoc_fpgaloadrbf.cmm "~~~~/<ep5csxfc6.rbf>" 0x100000
; @Board: -
; @Chip: CYCLONEVSOC
; @Author: AME
; @Copyright: (C) 1989-2019 Lauterbach GmbH, licensed for use with TRACE32(R) only
; $Id: cyclonevsoc_fpgaloadrbf.cmm 15223 2019-11-05 16:29:45Z bschroefel $
; --------------------------------------------------------------------------------

PRIVATE &RAM_START_ADRESS &FILE_NAME
ENTRY &FILE_NAME %LINE &RAM_START_ADRESS

; --------------------------------------------------------------------------------
; parse arguments
&FILE_NAME=STRing.Replace("&FILE_NAME","""","",0.)
IF !OS.FILE("&FILE_NAME")
(
  GOSUB PrintUsage
  ENDDO FALSE()
)
&ram_start=STRing.SCANAndExtract("&RAM_START_ADRESS","0x","")
IF "&ram_start"==""
(
  GOSUB PrintUsage
  ENDDO FALSE()
)
; ensure parameter is HEX and round down to the nearest 16byte
&ram_start="0x&ram_start"
&ram_start=(&ram_start+0x10)&~0xf

IF STATE.RUN()
  Break.direct

; check if &ram_start is accessible
Data.Test &ram_start++0xfff
IF FOUND()
(
  GOSUB PrintUsage
  ENDDO FALSE()
)

; --------------------------------------------------------------------------------
; load rbf file to DRAM
PRIVATE &rbf_addr &rbf_size &dma_prog_start

&dma_prog_start=&ram_start
&rbf_addr=&ram_start+0x200
&rbf_size=OS.FILE.SIZE("&FILE_NAME")
&rbf_size="0x"+FORMAT.HEX(1.,&rbf_size)

Data.LOAD.Binary "&FILE_NAME" EAHB:&rbf_addr /NoCLEAR /NosYmbol


; --------------------------------------------------------------------------------
; actual fpga programming phase starts here
Data.Set A:0xFFD08028 %Long 0x0         //Disable all signals from hps peripheral controller to fpga
Data.Set A:0xFFC25080 %Long 0x0         //Disable all signals from FPGA to HPS SDRAM
Data.Set A:0xFFD0501C %Long 0xffffffff  //Disable all axi bridge (hps2fpga, lwhps2fpga & fpga2hps)
Data.Set A:0xFF800000 %Long 0x1         //Unmap the bridges from NIC-301
LOCAL &msel
&msel=Data.Long(A:0xFF706000)
&msel=&msel&0xF8
&msel=&msel/0x8
IF (&msel&0x8)!=0
(
  ; FPPx32
  Data.Set A:0xFF706004 %Long (Data.Long(A:0xFF706004)|0x200) //Set the cfg width
  LOCAL &ratio
  &ratio=0x1
  IF (&msel&0x3)==0x0
  (
    &ratio=0x0
  )
  ELSE IF (&msel&0x3)==0x1
  (
    &ratio=0x80
  )
  ELSE IF (&msel&0x3)==0x2
  (
    &ratio=0xC0
  )
  IF &ratio!=0x1
  (
    Data.Set A:0xFF706004 %Long ((Data.Long(A:0xFF706004)&~0xC0)|&ratio) //Set CD ratio
  )
)
ELSE
(
  ; FPPx16
  Data.Set A:0xFF706004 %Long (Data.Long(A:0xFF706004)&~0x200) //Set the cfg width
  LOCAL &ratio
  &ratio=0x1
  IF (&msel&0x3)==0x0
  (
    &ratio=0x0
  )
  ELSE IF (&msel&0x3)==0x1
  (
    &ratio=0x40
  )
  ELSE IF (&msel&0x3)==0x2
  (
    &ratio=0x80
  )
  IF &ratio!=0x1
  (
    Data.Set A:0xFF706004 %Long ((Data.Long(A:0xFF706004)&~0xC0)|&ratio) //Set CD ratio
  )
)
Data.Set A:0xFF706004 %Long Data.Long(A:0xFF706004)&~0x2 //To enable FPGA Manager configuration
Data.Set A:0xFF706004 %Long Data.Long(A:0xFF706004)|0x1 //To enable FPGA Manager drive over configuration line
Data.Set A:0xFF706004 %Long Data.Long(A:0xFF706004)|0x4 //Put FPGA into reset phase
WAIT (Data.Long(A:0xFF706000)&0x7)==0x1 2.s
IF (Data.Long(A:0xFF706000)&0x7)!=0x1 //If not in reset state, return error
(
  PRINT %ERROR "Fatal Error."
  ENDDO FALSE()
)

Data.Set A:0xFF706004 %Long Data.Long(A:0xFF706004)&~0x4 //Release FPGA from reset phase
WAIT (Data.Long(A:0xFF706000)&0x7)==0x2 2.s
IF (Data.Long(A:0xFF706000)&0x7)!=0x2 //If not in configuration state, return error
(
  PRINT %ERROR "Fatal Error."
  ENDDO FALSE()
)
Data.Set A:0xFF70684C %Long 0xFFF //Clear all interrupts in CB Monitor
Data.Set A:0xFF706004 %Long Data.Long(A:0xFF706004)|0x100 //Enable AXI configuration

; --------------------------------------------------------------------------------
; Write the RBF data from DRAM to FPGA Manager using DMAC Channel 0
LOCAL &mb &rest &kb256 &kb256rest &kb &kbrest &bytes &bytesrest &dma_prog_pointer
&mb=&rbf_size/(0x400*0x400)
&rest=&rbf_size-(&mb*0x400*0x400)
&kb256=&rest/(0x100*0x400)
&kb256rest=&rest-(&kb256*0x100*0x400)
&kb=&kb256rest/(0x400)
&kbrest=&kb256rest-(&kb*0x400)
&bytes=&kbrest/0x4
&bytesrest=&kbrest-(&bytes*0x4)
&dma_prog_pointer=&dma_prog_start

;DMAMOV SAR
Data.Set &dma_prog_pointer %Word 0x00BC
Data.Set &dma_prog_pointer+0x2 %Long &rbf_addr
;DMAMOV DAR
Data.Set &dma_prog_pointer+0x6 %Word 0x02BC
Data.Set &dma_prog_pointer+0x8 %Long 0xFFB90000
;DMAMOV CCR
Data.Set &dma_prog_pointer+0xC %Word 0x01BC
Data.Set &dma_prog_pointer+0xE %Long 0x000D0035
&dma_prog_pointer=&dma_prog_pointer+0x12
WHILE &mb>0x0
(
  ;DMALP
  Data.Set &dma_prog_pointer %Word 0xFF22
    ;DMALP
    Data.Set &dma_prog_pointer+0x2 %Word 0xFF20
      ;DMALD
      Data.Set &dma_prog_pointer+0x4 %Byte 0x04
      ;DMALD
      Data.Set &dma_prog_pointer+0x5 %Byte 0x04
      ;DMAST
      Data.Set &dma_prog_pointer+0x6 %Byte 0x08
      ;DMAST
      Data.Set &dma_prog_pointer+0x7 %Byte 0x08
    ;DMALPEND
    Data.Set &dma_prog_pointer+0x8 %Word 0x0438
  ;DMALPEND
  Data.Set &dma_prog_pointer+0xA %Word 0x083C
  &dma_prog_pointer=&dma_prog_pointer+0xC
  &mb=&mb-1
)
;DMAMOV CCR
Data.Set &dma_prog_pointer %Word 0x01BC
Data.Set &dma_prog_pointer+0x2 %Long 0x00010005
&dma_prog_pointer=&dma_prog_pointer+0x6
WHILE &kb256>0x0
(
  ;DMALP
  Data.Set &dma_prog_pointer %Word 0xFF22
    ;DMALP
    Data.Set &dma_prog_pointer+0x2 %Word 0xFF20
      ;DMALD
      Data.Set &dma_prog_pointer+0x4 %Byte 0x04
      ;DMALD
      Data.Set &dma_prog_pointer+0x5 %Byte 0x04
      ;DMAST
      Data.Set &dma_prog_pointer+0x6 %Byte 0x08
      ;DMAST
      Data.Set &dma_prog_pointer+0x7 %Byte 0x08
    ;DMALPEND
    Data.Set &dma_prog_pointer+0x8 %Word 0x0438
  ;DMALPEND
  Data.Set &dma_prog_pointer+0xA %Word 0x083C
  &dma_prog_pointer=&dma_prog_pointer+0xC
  &kb256=&kb256-1
)
IF &kb>0x0
(
  ;DMALP
  Data.Set &dma_prog_pointer %Word (0x22+(&kb*0x100))
    ;DMALP
    Data.Set &dma_prog_pointer+0x2 %Word 0xFF20
      ;DMALD
      Data.Set &dma_prog_pointer+0x4 %Byte 0x04
      ;DMALD
      Data.Set &dma_prog_pointer+0x5 %Byte 0x04
      ;DMAST
      Data.Set &dma_prog_pointer+0x6 %Byte 0x08
      ;DMAST
      Data.Set &dma_prog_pointer+0x7 %Byte 0x08
    ;DMALPEND
    Data.Set &dma_prog_pointer+0x8 %Word 0x0438
  ;DMALPEND
  Data.Set &dma_prog_pointer+0xA %Word 0x083C
  &dma_prog_pointer=&dma_prog_pointer+0xC
)
IF &bytes>0x0
(
  ;DMALP
  Data.Set &dma_prog_pointer %Word (0x22+(&kb*0x100))
    ;DMALD
    Data.Set &dma_prog_pointer+0x2 %Byte 0x04
    ;DMAST
    Data.Set &dma_prog_pointer+0x3 %Byte 0x08
  ;DMALPEND
  Data.Set &dma_prog_pointer+0x4 %Word 0x023C
  &dma_prog_pointer=&dma_prog_pointer+0x6
)
IF &bytesrest>0x0
(
  ;DMALD
  Data.Set &dma_prog_pointer %Byte 0x04
  ;DMAST
  Data.Set &dma_prog_pointer+0x1 %Byte 0x08
  &dma_prog_pointer=&dma_prog_pointer+0x2
)
;DMAEND
Data.Set &dma_prog_pointer %Byte 0x00

; DBGINST0 Register -> DMAGO, Channel 0, Debug Manager
Data.Set A:0xFFE01D08 %Long 0x00A00000
; DBGINST1 Register -> start of DMA Program
Data.Set A:0xFFE01D0C %Long &dma_prog_start
; write DBGCMD Register -> START
Data.Set A:0xFFE01D04 %Long 0x0

; wait till DMA IDLE
WAIT 0.2s
WAIT Data.Long(A:0xFFE01D00)==0x0 10.s
; wait for status of DMA Channel 0
WAIT (Data.Long(A:0xFFE01100)&0xF)==0x0 1.s
; check status of DMA Channel 0
IF (Data.Long(A:0xFFE01100)&0xF)!=0x0
(
  PRINT "Error - DMA transaction failed."
  ENDDO FALSE()
)

ENDDO TRUE()
; --------------------------------------------------------------------------------
; Subroutines
; --------------------------------------------------------------------------------

PrintUsage:
  PRINT "Usage:"
  PRINT "  DO cyclonevsoc_fpgaloadrbf.cmm ""<PathTo>/<filename>.rbf"" <DRamAddress>"
  PRINT "  <filename>.rbf : Path and filename of the FPGA Design to load."
  PRINT "                   Must be in Raw-Binary-Format."
  PRINT "  <DRamAddress>  : Base Address in DRAM where the RBF file can be stored."
  PRINT "                   Memory content is not preserved."
  PRINT %ERROR "Invalid Usage! Type AREA for more details."
  RETURN
