# Copyright © 2018-2026 Johan Cockx, Matic Kukovec & Kristof Mulier
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

# SPDX-License-Identifier: GPL-3.0-or-later

from __future__ import annotations
from typing import *

q = "'"
dq = '"'
bsl = "\\"


def get_openocd_chip_cfg(
    chipname: Optional[str],
    target_file: Optional[str],
    *args,
    **kwargs,
) -> str:
    """The parameters passed here are extracted from a 'chip_dict' which is
    already overridden by the board dictionary."""
    if chipname is None:
        return "# Cannot generate OpenOCD config file"

    content = """
# CHIP HPM6750 SINGLE-CORE MODE
# =============================
# The following OpenOCD statements define the HPM6750 chip in single-core mode. Comment or delete
# these statements if you want to work in dual-core mode.
set _CHIP hpm6750
set _CPUTAPID 0x1000563D
jtag newtap $_CHIP cpu -irlen 5 -expected-id $_CPUTAPID
set _TARGET0 $_CHIP.cpu0
target create $_TARGET0 riscv -chain-position $_CHIP.cpu -coreid 0
$_TARGET0 configure -work-area-phys 0x00000000 -work-area-size 0x20000 -work-area-backup 0
targets $_TARGET0

# CHIP HPM6750 DUAL-CORE MODE
# ===========================
# The following OpenOCD statements define the HPM6750 chip in dual-core mode. They are commented
# out right now. If you want to work in dual-core mode, uncomment these statements and comment or
# delete the single-core mode statements.
# set _CHIP hpm6750
# set _CPUTAPID 0x1000563D
# jtag newtap $_CHIP cpu -irlen 5 -expected-id $_CPUTAPID
# set _TARGET0 $_CHIP.cpu0
# target create $_TARGET0 riscv -chain-position $_CHIP.cpu -coreid 0
# $_TARGET0 configure -work-area-phys 0x00000000 -work-area-size 0x20000 -work-area-backup 0
# targets $_TARGET0
# proc dmi_write {reg value} {
#     $::_TARGET0 riscv dmi_write ${reg} ${value}
# }
# proc dmi_read {reg} {
#     set v [$::_TARGET0 riscv dmi_read ${reg}]
#     return ${v}
# }
# proc dmi_write_memory {addr value} {
#     dmi_write 0x39 ${addr}
#     dmi_write 0x3C ${value}
# }
# proc dmi_read_memory {addr} {
#     set sbcs [expr 0x100000 | [dmi_read 0x38]]
#     dmi_write 0x38 ${sbcs}
#     dmi_write 0x39 ${addr}
#     set value [dmi_read 0x3C]
#     return ${value}
# }
# proc release_core1 {} {
#     set chip_rev [dmi_read_memory 0x2001FF00]
#     if {$chip_rev != 0x56010100 } {
#         # set start point for core1
#         dmi_write_memory 0xF4002C08 0x20016284
#     } else {
#         dmi_write_memory 0xF4002C08 0x2001660c
#     }
#     # set boot flag for core1
#     dmi_write_memory 0xF4002C0C 0xC1BEF1A9
#     # release core1
#     dmi_write_memory 0xF4002C00 0x1000
# }
# set _TARGET1 $_CHIP.cpu1
# target create $_TARGET1 riscv -chain-position $_CHIP.cpu -coreid 1
# $_TARGET1 configure -work-area-phys 0x00000000 -work-area-size 0x20000 -work-area-backup 0
# $_TARGET1 configure -event examine-start {
#     release_core1
# }
# $_TARGET1 configure -event reset-deassert-pre {
#     $::_TARGET0 arp_poll
#     release_core1
# }

# BOARD HPM6750EVKMINI
# ====================
# The following OpenOCD statements define the HPM6750EVKMINI board.
# openocd flash driver argument:
#   - ARG7:
#       [31:28] Flash probe type
#         0 - SFDP SDR / 1 - SFDP DDR
#         2 - 1-4-4 Read (0xEB, 24-bit address) / 3 - 1-2-2 Read(0xBB, 24-bit address)
#         4 - HyperFLASH 1.8V / 5 - HyperFLASH 3V
#         6 - OctaBus DDR (SPI -> OPI DDR)
#         8 - Xccela DDR (SPI -> OPI DDR)
#         10 - EcoXiP DDR (SPI -> OPI DDR)
#       [27:24] Command Pads after Power-on Reset
#         0 - SPI / 1 - DPI / 2 - QPI / 3 - OPI
#       [23:20] Command Pads after Configuring FLASH
#         0 - SPI / 1 - DPI / 2 - QPI / 3 - OPI
#       [19:16] Quad Enable Sequence (for the device support SFDP 1.0 only)
#         0 - Not needed
#         1 - QE bit is at bit 6 in Status Register 1
#         2 - QE bit is at bit1 in Status Register 2
#         3 - QE bit is at bit7 in Status Register 2
#         4 - QE bit is at bit1 in Status Register 2 and should be programmed by 0x31
#       [15:8] Dummy cycles
#         0 - Auto-probed / detected / default value
#         Others - User specified value, for DDR read, the dummy cycles should be 2 * cycles on FLASH datasheet
#       [7:4] Misc.
#         0 - Not used
#         1 - SPI mode
#         2 - Internal loopback
#         3 - External DQS
#       [3:0] Frequency option
#         1 - 30MHz / 2 - 50MHz / 3 - 66MHz / 4 - 80MHz / 5 - 100MHz / 6 - 120MHz / 7 - 133MHz / 8 - 166MHz
#   - ARG8:
#       [31:20]  Reserved
#       [19:16] IO voltage
#         0 - 3V / 1 - 1.8V
#       [15:12] Pin group
#         0 - 1st group / 1 - 2nd group
#       [11:8] Connection selection
#         0 - CA_CS0 / 1 - CB_CS0 / 2 - CA_CS0 + CB_CS0 (Two FLASH connected to CA and CB respectively)
#       [7:0] Drive Strength
#         0 - Default value

# xpi0 configs
#   - flash driver:     hpm_xpi
#   - flash ctrl index: 0xF3040000
#   - base address:     0x80000000
#   - flash size:       0x1000000
#   - flash option0:    0x7
flash bank xpi0 hpm_xpi 0x80000000 0x1000000 1 1 $_TARGET0 0xF3040000 0x7

proc init_clock {} {
    $::_TARGET0 riscv dmi_write 0x39 0xF4002000
    $::_TARGET0 riscv dmi_write 0x3C 0x1

    $::_TARGET0 riscv dmi_write 0x39 0xF4002000
    $::_TARGET0 riscv dmi_write 0x3C 0x2

    $::_TARGET0 riscv dmi_write 0x39 0xF4000800
    $::_TARGET0 riscv dmi_write 0x3C 0xFFFFFFFF

    $::_TARGET0 riscv dmi_write 0x39 0xF4000810
    $::_TARGET0 riscv dmi_write 0x3C 0xFFFFFFFF

    $::_TARGET0 riscv dmi_write 0x39 0xF4000820
    $::_TARGET0 riscv dmi_write 0x3C 0xFFFFFFFF

    $::_TARGET0 riscv dmi_write 0x39 0xF4000830
    $::_TARGET0 riscv dmi_write 0x3C 0xFFFFFFFF
    echo "clocks has been enabled!"
}

proc init_sdram { } {
# configure femc frequency
# 133Mhz pll1_clk0: 266Mhz divide by 2
    #$::_TARGET0 riscv dmi_write 0x39 0xF4001820
    #$::_TARGET0 riscv dmi_write 0x3C 0x201
# 166Mhz pll2_clk0: 333Mhz divide by 2
    $::_TARGET0 riscv dmi_write 0x39 0xF4001820
    $::_TARGET0 riscv dmi_write 0x3C 0x401

    # PD13
    $::_TARGET0 riscv dmi_write 0x39 0xF4040368
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PD12
    $::_TARGET0 riscv dmi_write 0x39 0xF4040360
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PD10
    $::_TARGET0 riscv dmi_write 0x39 0xF4040350
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PD09
    $::_TARGET0 riscv dmi_write 0x39 0xF4040348
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PD08
    $::_TARGET0 riscv dmi_write 0x39 0xF4040340
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PD07
    $::_TARGET0 riscv dmi_write 0x39 0xF4040338
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PD06
    $::_TARGET0 riscv dmi_write 0x39 0xF4040330
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PD05
    $::_TARGET0 riscv dmi_write 0x39 0xF4040328
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PD04
    $::_TARGET0 riscv dmi_write 0x39 0xF4040320
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PD03
    $::_TARGET0 riscv dmi_write 0x39 0xF4040318
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PD02
    $::_TARGET0 riscv dmi_write 0x39 0xF4040310
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PD01
    $::_TARGET0 riscv dmi_write 0x39 0xF4040308
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PD00
    $::_TARGET0 riscv dmi_write 0x39 0xF4040300
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC29
    $::_TARGET0 riscv dmi_write 0x39 0xF40402E8
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC28
    $::_TARGET0 riscv dmi_write 0x39 0xF40402E0
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC27
    $::_TARGET0 riscv dmi_write 0x39 0xF40402D8
    $::_TARGET0 riscv dmi_write 0x3C 0xC

    # PC22
    $::_TARGET0 riscv dmi_write 0x39 0xF40402B0
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC21
    $::_TARGET0 riscv dmi_write 0x39 0xF40402A8
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC17
    $::_TARGET0 riscv dmi_write 0x39 0xF4040288
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC15
    $::_TARGET0 riscv dmi_write 0x39 0xF4040278
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC12
    $::_TARGET0 riscv dmi_write 0x39 0xF4040260
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC11
    $::_TARGET0 riscv dmi_write 0x39 0xF4040258
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC10
    $::_TARGET0 riscv dmi_write 0x39 0xF4040250
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC09
    $::_TARGET0 riscv dmi_write 0x39 0xF4040248
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC08
    $::_TARGET0 riscv dmi_write 0x39 0xF4040240
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC07
    $::_TARGET0 riscv dmi_write 0x39 0xF4040238
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC06
    $::_TARGET0 riscv dmi_write 0x39 0xF4040230
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC05
    $::_TARGET0 riscv dmi_write 0x39 0xF4040228
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC04
    $::_TARGET0 riscv dmi_write 0x39 0xF4040220
    $::_TARGET0 riscv dmi_write 0x3C 0xC

    # PC14
    $::_TARGET0 riscv dmi_write 0x39 0xF4040270
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC13
    $::_TARGET0 riscv dmi_write 0x39 0xF4040268
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC16
    # $::_TARGET0 riscv dmi_write 0x39 0xF4040280
    #$::_TARGET0 riscv dmi_write 0x3C 0x1000C
    # PC26
    $::_TARGET0 riscv dmi_write 0x39 0xF40402D0
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC25
    $::_TARGET0 riscv dmi_write 0x39 0xF40402C8
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC19
    $::_TARGET0 riscv dmi_write 0x39 0xF4040298
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC18
    $::_TARGET0 riscv dmi_write 0x39 0xF4040290
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC23
    $::_TARGET0 riscv dmi_write 0x39 0xF40402B8
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC24
    $::_TARGET0 riscv dmi_write 0x39 0xF40402C0
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC30
    $::_TARGET0 riscv dmi_write 0x39 0xF40402F0
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC31
    $::_TARGET0 riscv dmi_write 0x39 0xF40402F8
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC02
    $::_TARGET0 riscv dmi_write 0x39 0xF4040210
    $::_TARGET0 riscv dmi_write 0x3C 0xC
    # PC03
    $::_TARGET0 riscv dmi_write 0x39 0xF4040218
    $::_TARGET0 riscv dmi_write 0x3C 0xC

    # femc configuration
    $::_TARGET0 riscv dmi_write 0x39 0xF3050000
    $::_TARGET0 riscv dmi_write 0x3C 0x1
    sleep 10
    $::_TARGET0 riscv dmi_write 0x39 0xF3050000
    $::_TARGET0 riscv dmi_write 0x3C 0x2
    $::_TARGET0 riscv dmi_write 0x39 0xF3050008
    $::_TARGET0 riscv dmi_write 0x3C 0x30524
    $::_TARGET0 riscv dmi_write 0x39 0xF305000C
    $::_TARGET0 riscv dmi_write 0x3C 0x6030524
    $::_TARGET0 riscv dmi_write 0x39 0xF3050000
    $::_TARGET0 riscv dmi_write 0x3C 0x10000000

    # 16MB
    $::_TARGET0 riscv dmi_write 0x39 0xF3050010
    $::_TARGET0 riscv dmi_write 0x3C 0x40000019
    $::_TARGET0 riscv dmi_write 0x39 0xF3050014
    $::_TARGET0 riscv dmi_write 0x3C 0
    # 16-bit
    $::_TARGET0 riscv dmi_write 0x39 0xF3050040
    $::_TARGET0 riscv dmi_write 0x3C 0xf31

    # 133Mhz configuration
    #$::_TARGET0 riscv dmi_write 0x39 0xF3050044
    #$::_TARGET0 riscv dmi_write 0x3C 0x884e22
    # 166Mhz configuration
    $::_TARGET0 riscv dmi_write 0x39 0xF3050044
    $::_TARGET0 riscv dmi_write 0x3C 0x884e33

    $::_TARGET0 riscv dmi_write 0x39 0xF3050048
    $::_TARGET0 riscv dmi_write 0x3C 0x1020d0d
    $::_TARGET0 riscv dmi_write 0x39 0xF3050048
    $::_TARGET0 riscv dmi_write 0x3C 0x1020d0d
    $::_TARGET0 riscv dmi_write 0x39 0xF305004C
    $::_TARGET0 riscv dmi_write 0x3C 0x2020300

    # config delay cell
    $::_TARGET0 riscv dmi_write 0x39 0xF3050150
    $::_TARGET0 riscv dmi_write 0x3C 0x3b
    $::_TARGET0 riscv dmi_write 0x39 0xF3050150
    $::_TARGET0 riscv dmi_write 0x3C 0x203b

    $::_TARGET0 riscv dmi_write 0x39 0xF3050094
    $::_TARGET0 riscv dmi_write 0x3C 0
    $::_TARGET0 riscv dmi_write 0x39 0xF3050098
    $::_TARGET0 riscv dmi_write 0x3C 0

    # precharge all
    $::_TARGET0 riscv dmi_write 0x39 0xF3050090
    $::_TARGET0 riscv dmi_write 0x3C 0x40000000
    $::_TARGET0 riscv dmi_write 0x39 0xF305009C
    $::_TARGET0 riscv dmi_write 0x3C 0xA55A000F
    sleep 500
    $::_TARGET0 riscv dmi_write 0x39 0xF305003C
    $::_TARGET0 riscv dmi_write 0x3C 0x3
    # auto refresh
    $::_TARGET0 riscv dmi_write 0x39 0xF305009C
    $::_TARGET0 riscv dmi_write 0x3C 0xA55A000C
    sleep 500
    $::_TARGET0 riscv dmi_write 0x39 0xF305003C
    $::_TARGET0 riscv dmi_write 0x3C 0x3
    $::_TARGET0 riscv dmi_write 0x39 0xF305009C
    $::_TARGET0 riscv dmi_write 0x3C 0xA55A000C
    sleep 500
    $::_TARGET0 riscv dmi_write 0x39 0xF305003C
    $::_TARGET0 riscv dmi_write 0x3C 0x3

    # set mode
    $::_TARGET0 riscv dmi_write 0x39 0xF30500A0
    $::_TARGET0 riscv dmi_write 0x3C 0x33
    $::_TARGET0 riscv dmi_write 0x39 0xF305009C
    $::_TARGET0 riscv dmi_write 0x3C 0xA55A000A
    sleep 500
    $::_TARGET0 riscv dmi_write 0x39 0xF305003C
    $::_TARGET0 riscv dmi_write 0x3C 0x3

    $::_TARGET0 riscv dmi_write 0x39 0xF305004C
    $::_TARGET0 riscv dmi_write 0x3C 0x2020301
    echo "SDRAM has been initialized"
}
$_TARGET0 configure -event reset-init {
    init_clock
    init_sdram
}
$_TARGET0 configure -event gdb-attach {
    reset halt
}
"""
    return content
