Skip to content

Commit

Permalink
LDS generation updated (#14)
Browse files Browse the repository at this point in the history
* Linker generation script cleaned and simplified.

* PeakRDL-socgen error message corrected.

* firmware hex file generation set to per byte format.

* Generated hex file per byte format (default).

* Support for multiple systemrdl top parameters overwritten.

* gen_lds cmake func corrected for multi param argument generation.

---------

Co-authored-by: Benoit Denkinger <[email protected]>
  • Loading branch information
benoitdenkinger and Benoit Denkinger authored Jul 19, 2024
1 parent 8a3dc9a commit a41eb84
Show file tree
Hide file tree
Showing 7 changed files with 22 additions and 78 deletions.
6 changes: 3 additions & 3 deletions cmake/firmware/fw_utils.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,10 @@ function(gen_hex_files EXE)
add_custom_command(TARGET ${EXE}
POST_BUILD
BYPRODUCTS ${HEX_FILE} ${HEX_TEXT_FILE} ${HEX_DATA_FILE}
COMMAND ${CMAKE_OBJCOPY} -O verilog --verilog-data-width=4 ${EXECUTABLE} ${HEX_FILE}
COMMAND ${CMAKE_OBJCOPY} -O verilog --verilog-data-width=4 --gap-fill 0x0000 ${TEXT_SECTION} ${EXECUTABLE} ${HEX_TEXT_FILE}
COMMAND ${CMAKE_OBJCOPY} -O verilog ${EXECUTABLE} ${HEX_FILE}
COMMAND ${CMAKE_OBJCOPY} -O verilog --gap-fill 0x0000 ${TEXT_SECTION} ${EXECUTABLE} ${HEX_TEXT_FILE}
# TODO: find an automatic way to 'correct' the VMA for loading during simulation
COMMAND ${CMAKE_OBJCOPY} -O verilog --verilog-data-width=4 --gap-fill 0x0000 --adjust-vma=-0x10000000 ${DATA_SECTION} ${EXECUTABLE} ${HEX_DATA_FILE}
COMMAND ${CMAKE_OBJCOPY} -O verilog --gap-fill 0x0000 --adjust-vma=-0x10000000 ${DATA_SECTION} ${EXECUTABLE} ${HEX_DATA_FILE}
COMMENT "Generating ${width} bit hex file for ${EXE}"
)

Expand Down
3 changes: 2 additions & 1 deletion cmake/firmware/linker_script/gen_lds.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ function(gen_lds IP_LIB)
set(OVERWRITTEN_PARAMETERS "")
# Process any specified parameters to overwrite
if(ARG_PARAMETERS)
set(OVERWRITTEN_PARAMETERS "-p")
foreach(PARAM ${ARG_PARAMETERS})
string(APPEND OVERWRITTEN_PARAMETERS "-p${PARAM}")
set(OVERWRITTEN_PARAMETERS "${OVERWRITTEN_PARAMETERS}" "${PARAM}")
endforeach()
endif()

Expand Down
77 changes: 11 additions & 66 deletions cmake/firmware/linker_script/src/gen_linker_script.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,12 @@ class RDL2LdsExporter(RDLListener):
- :func:`isSwEx`
- :func:`isSwWr`
- :func:`isBoot`
- :func:`isStack`
- :func:`isData`
- :func:`isBss`
- :func:`get_sections_prop`
- :func:`getStackMem`
- :func:`getProgramMem`
- :func:`getTextMem`
- :func:`getDataMem`
- :func:`getBssMem`
- :func:`getBootMem`
- :func:`getSwAcc`
- :func:`write_sections`
- :func:`export`
- :func:`process_template``
"""
Expand Down Expand Up @@ -63,24 +58,17 @@ def isSwWr(self, mem : MemNode) -> bool:
return True
return False

def isBoot(self, mem : MemNode) -> bool:
def isText(self, mem : MemNode) -> bool:
"""Returns True if section is contains the bootloader."""
sections = self.get_sections_prop(mem)
if "boot" in sections:
return True
return False

def isStack(self, mem : MemNode) -> bool:
"""Returns True if section contains the stack."""
sections = self.get_sections_prop(mem)
if "stack" in sections:
if "text" in sections:
return True
return False

def isHeap(self, mem : MemNode) -> bool:
"""Returns True if section contains the heap."""
def isBoot(self, mem : MemNode) -> bool:
"""Returns True if section is contains the bootloader."""
sections = self.get_sections_prop(mem)
if "heap" in sections:
if "boot" in sections:
return True
return False

Expand All @@ -91,46 +79,20 @@ def isData(self, mem : MemNode) -> bool:
return True
return False

def isBss(self, mem : MemNode) -> bool:
"""Returns True if section contains the bss (uninitialized global or static variables)."""
sections = self.get_sections_prop(mem)
if "bss" in sections:
return True
return False

def get_sections_prop(self, m : MemNode) -> List[str]:
"""Returns a list of string corresponding to the section properties."""
sections = m.get_property('sections').split('|')
for s in sections:
assert_m = f"Illegal property for sections: {s} of memory: {m.inst_name} in addrmap: {m.parent.inst_name}"
assert s in ['text', 'data', 'bss', 'boot', 'stack', 'heap'], assert_m
assert s in ['text', 'data', 'boot'], assert_m

return sections

def getStackMem(self, mems: List[MemNode]) -> MemNode:
stack_mems = []
for m in mems:
if self.isStack(m):
stack_mems.append(m)
assert len(stack_mems) == 1, f"Exactly 1 memory with section stack is allowed and required {stack_mems}" # TODO

return stack_mems[0]

def getHeapMem(self, mems: List[MemNode]) -> MemNode:
heap_mems = []
for m in mems:
if self.isHeap(m):
heap_mems.append(m)
assert len(heap_mems) == 1, f"Exactly 1 memory with section heap is allowed and required {heap_mems}" # TODO

return heap_mems[0]


def getProgramMem(self, mems: List[MemNode]) -> MemNode:
def getTextMem(self, mems: List[MemNode]) -> MemNode:
"""Returns the program/instruction/text MemNode."""
prog_mems = []
for m in mems:
if self.isSwEx(m) and not self.isBoot(m):
if self.isSwEx(m) and self.isText(m):
prog_mems.append(m)
assert len(prog_mems) == 1, f"Exactly 1 memory with program memory is allowed and required {prog_mems}" # TODO

Expand All @@ -146,16 +108,6 @@ def getDataMem(self, mems: List[MemNode]) -> MemNode:

return data_mems[0]

def getBssMem(self, mems: List[MemNode]) -> MemNode:
"""Returns the bss MemNode."""
data_mems = []
for m in mems:
if self.isData(m):
data_mems.append(m)
assert len(data_mems) == 1, f"Exactly 1 memory with program memory is allowed and required {data_mems}" # TODO

return data_mems[0]

def getBootMem(self, mems: List[MemNode]) -> "MemNode | None":
"""Returns the boot MemNode."""
boot_mems = []
Expand Down Expand Up @@ -186,11 +138,8 @@ def export(self,
'regs' : self.regs
}

# text = self.process_template(context, "lds.j2")
text = self.process_template(context, "linker.lds.j2")

# assert(node.type_name is not None)
# out_file = os.path.join(outfile, node.type_name + ".lds")
with open(outfile, 'w') as f:
f.write(text)

Expand All @@ -204,16 +153,13 @@ def process_template(self, context : dict, template : str) -> str:
env.filters.update({
'zip' : zip,
'int' : int,
'isBoot' : self.isBoot,
'isSwWr' : self.isSwWr,
'isSwEx' : self.isSwEx,
'getSwAcc' : self.getSwAcc,
'getStackMem' : self.getStackMem,
'getProgramMem' : self.getProgramMem,
'getTextMem' : self.getTextMem,
'getBootMem' : self.getBootMem,
'getDataMem' : self.getDataMem,
'getBssMem' : self.getBssMem,
})
})

res = env.get_template(template).render(context)
return res
Expand Down Expand Up @@ -264,7 +210,6 @@ def main():
)



if __name__ == "__main__":
main()

5 changes: 1 addition & 4 deletions cmake/firmware/linker_script/src/template/linker.lds.j2
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,9 @@ MEMORY {
{% endfor %}
}

{# {% set stack_mem = mems|getStackMem %}
{% set heap_mem = mems|getHeapMem %} #}
{% set prog_mem = mems|getProgramMem %}
{% set prog_mem = mems|getTextMem %}
{% set boot_mem = mems|getBootMem %}
{% set data_mem = mems|getDataMem %}
{% set bss_mem = mems|getBssMem %}

{% for reg in regs %}
PROVIDE({{reg.inst_name}} = 0x{{ '%08x' % reg.absolute_address }});
Expand Down
2 changes: 1 addition & 1 deletion cmake/peakrdl/peakrdl_halcpp.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ function(peakrdl_halcpp IP_LIB)
set(OVERWRITTEN_PARAMETERS "")
if(ARG_PARAMETERS)
foreach(PARAM ${ARG_PARAMETERS})
string(APPEND OVERWRITTEN_PARAMETERS "-P${PARAM}")
set(OVERWRITTEN_PARAMETERS "${OVERWRITTEN_PARAMETERS}" "-P${PARAM}")
endforeach()
endif()

Expand Down
5 changes: 3 additions & 2 deletions cmake/peakrdl/peakrdl_socgen/peakrdl_socgen.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,11 @@ function(peakrdl_socgen IP_LIB)
endif()

# Used to overwrite the top level parameters
set(OVERWRITTEN_PARAMETERS_TARGET "")
set(OVERWRITTEN_PARAMETERS "")
if(ARG_PARAMETERS)
foreach(PARAM ${ARG_PARAMETERS})
string(APPEND OVERWRITTEN_PARAMETERS "-P${PARAM}")
set(OVERWRITTEN_PARAMETERS "${OVERWRITTEN_PARAMETERS}" "-P${PARAM}")
endforeach()
endif()

Expand Down Expand Up @@ -141,7 +142,7 @@ function(peakrdl_socgen IP_LIB)
string(REPLACE "\n" "" V_GEN "${V_GEN}")
list(REMOVE_DUPLICATES V_GEN)
else()
string(REPLACE ";" " " __CMD_STR "${__CMD}")
string(REPLACE ";" " " __CMD_STR "${__CMD_LF}")
message(FATAL_ERROR "Error no files generated from ${CMAKE_CURRENT_FUNCTION} for ${IP_LIB},
output of --list-files option: ${V_GEN} error output: ${ERROR_MSG} \n
Command Called: \n ${__CMD_STR}")
Expand Down
2 changes: 1 addition & 1 deletion cmake/sim/cocotb/cocotb_iverilog.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ function(cocotb_iverilog IP_LIB)
if(NOT COCOTB_LIB_DIR)
message(FATAL_ERROR "Cocotb lib directory variable not found. Make sure cocotb package is installed in the python venv. Error output: ${ERROR_MSG}.")
endif()
# Remove the line feed of the variable otherwise if breaks the below command
# Remove the line feed of the variable otherwise it breaks the below command
string(STRIP ${COCOTB_LIB_DIR} COCOTB_LIB_DIR)

# Get cocotb vpi library for icarus verilog
Expand Down

0 comments on commit a41eb84

Please sign in to comment.