From ca63d125091d2bc528658d7d54cebb0578535a7c Mon Sep 17 00:00:00 2001 From: Mateusz Karlic Date: Thu, 22 Sep 2022 12:32:31 +0200 Subject: [PATCH 01/12] json2renode: Add support for multicore builds --- litex/tools/litex_json2renode.py | 81 ++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/litex/tools/litex_json2renode.py b/litex/tools/litex_json2renode.py index 8beda26fa..22c6e5d54 100755 --- a/litex/tools/litex_json2renode.py +++ b/litex/tools/litex_json2renode.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 """ -Copyright (c) 2019-2021 Antmicro +Copyright (c) 2019-2022 Antmicro Renode platform definition (repl) and script (resc) generator for LiteX SoC. @@ -20,6 +20,8 @@ import argparse # and should not be generated automatically non_generated_mem_regions = ['ethmac', 'csr'] +# let's just fail if we access this prematurely +number_of_cores = None def get_descriptor(csr, name, size=None): res = { 'base': csr['csr_bases'][name], 'constants': {} } @@ -110,7 +112,7 @@ ethmac: Network.LiteX_Ethernet{} @ {{ interrupt_name = '{}_interrupt'.format(name) if interrupt_name in csr['constants']: - result += ' -> cpu@{}\n'.format( + result += ' -> plic@{}\n'.format( csr['constants'][interrupt_name]) result += """ @@ -204,6 +206,9 @@ def get_cpu_type(csr): return (kind, variant) +def get_cpu_count(csr): + config_cpu_count = csr['constants']['config_cpu_count'] + return config_cpu_count def generate_cpu(csr, time_provider): """ Generates definition of a CPU. @@ -214,62 +219,68 @@ def generate_cpu(csr, time_provider): kind, variant = get_cpu_type(csr) if kind == 'vexriscv' or kind == 'vexriscv_smp': - result = """ -cpu: CPU.VexRiscv @ sysbus + cpu_string = """ +CPU.VexRiscv @ sysbus """ if variant == 'linux': - result += """ + cpu_string += """ cpuType: "rv32ima" privilegeArchitecture: PrivilegeArchitecture.Priv1_10 """ elif variant in ["i", "im", "ima", "imac"]: - result += """ + cpu_string += """ cpuType: "rv32{}" """.format(variant) else: - result += """ + cpu_string += """ cpuType: "rv32im" """ if time_provider: - result += """ + cpu_string += """ timeProvider: {} """.format(time_provider) - return result elif kind == 'picorv32': - return """ -cpu: CPU.PicoRV32 @ sysbus + cpu_string = """ +CPU.PicoRV32 @ sysbus cpuType: "rv32imc" """ elif kind == 'minerva': - return """ -cpu: CPU.Minerva @ sysbus + cpu_string = """ +CPU.Minerva @ sysbus """ elif kind == 'ibex': - return """ -cpu: CPU.IbexRiscV32 @ sysbus + cpu_string = """ +CPU.IbexRiscV32 @ sysbus """ elif kind == 'cv32e40p': - result = """ -cpu: CPU.CV32E40P @ sysbus + cpu_string = """ +CPU.CV32E40P @ sysbus """ if variant == 'standard': - result += """ + cpu_string += """ cpuType: "rv32imc" """ else: - result += """ + cpu_string += """ cpuType: "rv32imc" """ if time_provider: - result += """ + cpu_string += """ timeProvider: {} """.format(time_provider) - return result else: raise Exception('Unsupported cpu type: {}'.format(kind)) + result = '' + for cpu_id in range(0, number_of_cores): + result += f""" +cpu{cpu_id}: {cpu_string.strip()} + hartId: {cpu_id} +""" + + return result def generate_peripheral(csr, name, **kwargs): """ Generates definition of a peripheral. @@ -298,7 +309,7 @@ def generate_peripheral(csr, name, **kwargs): for constant, val in peripheral['constants'].items(): if 'ignored_constants' not in kwargs or constant not in kwargs['ignored_constants']: if constant == 'interrupt': - result += ' -> cpu@{}\n'.format(val) + result += ' -> plic@{}\n'.format(val) else: result += ' {}: {}\n'.format(constant, val) @@ -418,11 +429,14 @@ def generate_clint(clint, frequency): result = """ clint: IRQControllers.CoreLevelInterruptor @ {} frequency: {} - [0, 1] -> cpu@[101, 100] + numberOfTargets: {} """.format(generate_sysbus_registration(clint, skip_braces=True, skip_size=True), - frequency) + frequency, number_of_cores) + + for cpu_id in range(0, number_of_cores): + result += f" [{2 * cpu_id}, {2 * cpu_id + 1}] -> cpu{cpu_id}@[101, 100]\n" return result @@ -431,13 +445,16 @@ def generate_plic(plic): # TODO: this is configuration for linux-on-litex-vexriscv - add support for other CPU types result = """ plic: IRQControllers.PlatformLevelInterruptController @ {} - [0, 1] -> cpu@[11, 9] numberOfSources: 31 - numberOfContexts: 2 + numberOfContexts: {} prioritiesEnabled: false """.format(generate_sysbus_registration(plic, skip_braces=True, - skip_size=True)) + skip_size=True), + 2 * number_of_cores) + + for cpu_id in range(0, number_of_cores): + result += f" [{2 * cpu_id}, {2 * cpu_id + 1}] -> cpu{cpu_id}@[11, 9]\n" return result @@ -521,7 +538,7 @@ peripherals_handlers = { }, 'interrupts': { # IRQ #100 in Renode's VexRiscv model is mapped to Machine Timer Interrupt - 'IRQ': lambda: 'cpu@100' + 'IRQ': lambda: 'cpu0@100' } }, 'ddrphy': { @@ -591,7 +608,8 @@ def generate_repl(csr, etherbone_peripherals, autoalign): peripherals and memory regions """ result = "" - + global number_of_cores + number_of_cores = get_cpu_count(csr) # RISC-V CPU in Renode requires memory region size # to be a multiple of 4KB - this is a known limitation @@ -761,9 +779,10 @@ showAnalyzer sysbus.uart Antmicro.Renode.Analyzers.LoggingUartAnalyzer # load LiteX BIOS to ROM result += """ sysbus LoadBinary @{} {} -cpu PC {} -""".format(args.bios_binary, rom_base, rom_base) +""".format(args.bios_binary, hex(rom_base)) + for cpu_id in range(0, number_of_cores): + result += f"cpu{cpu_id} PC {hex(rom_base)}\n" if args.tftp_ip: result += """ From 860ca8673e8f81231f445e17e9a56c23cc7e08fe Mon Sep 17 00:00:00 2001 From: Mateusz Karlic Date: Thu, 22 Sep 2022 13:25:45 +0200 Subject: [PATCH 02/12] json2renode: Use opensbi->base for bios binary --- litex/tools/litex_json2renode.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/litex/tools/litex_json2renode.py b/litex/tools/litex_json2renode.py index 22c6e5d54..d5e6e2050 100755 --- a/litex/tools/litex_json2renode.py +++ b/litex/tools/litex_json2renode.py @@ -774,15 +774,15 @@ showAnalyzer sysbus.uart showAnalyzer sysbus.uart Antmicro.Renode.Analyzers.LoggingUartAnalyzer """.format(cpu_type, args.repl) - rom_base = csr['memories']['rom']['base'] if 'rom' in csr['memories'] else None - if rom_base is not None and args.bios_binary: + opensbi_base = csr['memories']['opensbi']['base'] if 'opensbi' in csr['memories'] else None + if opensbi_base is not None and args.bios_binary: # load LiteX BIOS to ROM result += """ sysbus LoadBinary @{} {} -""".format(args.bios_binary, hex(rom_base)) +""".format(args.bios_binary, hex(opensbi_base)) for cpu_id in range(0, number_of_cores): - result += f"cpu{cpu_id} PC {hex(rom_base)}\n" + result += f"cpu{cpu_id} PC {hex(opensbi_base)}\n" if args.tftp_ip: result += """ From 55dcee16c310c0833a4d7d8b4c6c8292f8063a51 Mon Sep 17 00:00:00 2001 From: Mateusz Karlic Date: Thu, 22 Sep 2022 14:41:05 +0200 Subject: [PATCH 03/12] json2renode: Use spiflash->base instead of flash_boot_address --- litex/tools/litex_json2renode.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/litex/tools/litex_json2renode.py b/litex/tools/litex_json2renode.py index d5e6e2050..c07f909c6 100755 --- a/litex/tools/litex_json2renode.py +++ b/litex/tools/litex_json2renode.py @@ -811,16 +811,16 @@ connector Connect ethmac switch connector Connect host.tap switch """.format(args.configure_network) elif flash_binaries: - if 'flash_boot_address' not in csr['constants']: + if 'spiflash' not in csr['memories']: print('Warning! There is no flash memory to load binaries to') else: # load binaries to spiflash to boot from there for offset in flash_binaries: path = flash_binaries[offset] - flash_boot_address = int(csr['constants']['flash_boot_address'], 0) + offset + flash_boot_address = int(csr['memories']['spiflash']['base']) + offset - firmware_data = open(path, 'rb').read() + firmware_data = open(os.path.expanduser(path), 'rb').read() crc32 = zlib.crc32(firmware_data) result += 'sysbus WriteDoubleWord {} {}\n'.format(hex(flash_boot_address), hex(len(firmware_data))) From a9caeda30e3a43c4d99d9a48bcd7dd9888f5f8b5 Mon Sep 17 00:00:00 2001 From: Mateusz Karlic Date: Fri, 7 Oct 2022 12:12:27 +0200 Subject: [PATCH 04/12] json2renode: Fix typo --- litex/tools/litex_json2renode.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/tools/litex_json2renode.py b/litex/tools/litex_json2renode.py index c07f909c6..5665b5204 100755 --- a/litex/tools/litex_json2renode.py +++ b/litex/tools/litex_json2renode.py @@ -581,7 +581,7 @@ peripherals_handlers = { } -def genereate_etherbone_bridge(name, address, port): +def generate_etherbone_bridge(name, address, port): # FIXME: for now the width is fixed to 0x800 return """ {}: EtherboneBridge @ sysbus <{}, +0x800> @@ -649,7 +649,7 @@ def generate_repl(csr, etherbone_peripherals, autoalign): if name in etherbone_peripherals: # generate an etherbone bridge for the peripheral port = etherbone_peripherals[name] - result += genereate_etherbone_bridge(name, address, port) + result += generate_etherbone_bridge(name, address, port) pass else: # generate an actual model of the peripheral From 283a237876f56bf2087478132e161fc4c14c5a63 Mon Sep 17 00:00:00 2001 From: Mateusz Karlic Date: Tue, 11 Oct 2022 15:57:51 +0200 Subject: [PATCH 05/12] json2renode: Fix registration of GPIO peripherals --- litex/tools/litex_json2renode.py | 62 +++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/litex/tools/litex_json2renode.py b/litex/tools/litex_json2renode.py index 5665b5204..118c2fae8 100755 --- a/litex/tools/litex_json2renode.py +++ b/litex/tools/litex_json2renode.py @@ -506,6 +506,60 @@ def get_clock_frequency(csr): # has different names return csr['constants']['config_clock_frequency' if 'config_clock_frequency' in csr['constants'] else 'system_clock_frequency'] +def generate_gpio_port(csr, name, **kwargs): + peripheral = get_descriptor(csr, name) + + ints = '' + if 'interrupt' in kwargs: + ints += f' IRQ -> plic@{kwargs["interrupt"]}' + if 'connections' in kwargs: + for irq, target in zip(kwargs['connections'], kwargs['connections_targets']): + ints += f' {irq} -> {target}\n' + + result = """ +gpio_{}: GPIOPort.LiteX_GPIO @ {} + type: {} + enableIrq: {} +{} +""".format(name, + generate_sysbus_registration(peripheral, skip_braces=True), + kwargs['type'], + 'true' if kwargs['type'] != 'Type.Out' else 'false', + ints) + + return result + +def generate_switches(csr, name, **kwargs): + interrupt_name = '{}_interrupt'.format(name) + result = generate_gpio_port(csr, name, **{'type': 'Type.In', 'interrupt': csr['constants'][interrupt_name], **kwargs}) + + # Litex puts 4 by default into dts (litex_json2dts) + count = int(csr['constants'].get(f'{name}_ngpio', 4)) + + for i in range(0, count): + result += """ +{name}_{i}: Miscellaneous.Button @ {periph} {i} + -> {periph}@{i} +""".format(name=name, periph=f"gpio_{name}", i=i) + + return result + +def generate_leds(csr, name, **kwargs): + # Litex puts 4 by default into dts (litex_json2dts) + count = int(csr['constants'].get(f'{name}_ngpio', 4)) + + result = generate_gpio_port(csr, name, + **{'type': 'Type.Out', + 'connections': [*range(0, count)], + 'connections_targets': [f'leds_{i}@0' for i in range(0, count)], + **kwargs}) + + for i in range(0, count): + result += """ +{name}_{i}: Miscellaneous.LED @ {periph} {i} +""".format(name=name, periph=f"gpio_{name}", i=i) + + return result peripherals_handlers = { 'uart': { @@ -577,7 +631,13 @@ peripherals_handlers = { }, 'video_framebuffer_vtg': { 'handler': lambda *args, **kwargs: "", # This is handled by generate_video_framebuffer - } + }, + 'leds': { + 'handler': generate_leds, + }, + 'switches': { + 'handler': generate_switches, + }, } From 8b9ca8e9e93bac29bf886451485bbe178b81369a Mon Sep 17 00:00:00 2001 From: Mateusz Karlic Date: Fri, 14 Oct 2022 15:34:01 +0200 Subject: [PATCH 06/12] json2renode: Silence false warnings about unsupported peripherals --- litex/tools/litex_json2renode.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/litex/tools/litex_json2renode.py b/litex/tools/litex_json2renode.py index 118c2fae8..ced32904a 100755 --- a/litex/tools/litex_json2renode.py +++ b/litex/tools/litex_json2renode.py @@ -561,6 +561,13 @@ def generate_leds(csr, name, **kwargs): return result +def handled_peripheral(csr, name, **kwargs): + """ + Use this to silence warnings about unsupported peripherals, that are in reality emulated by other peripheral + e. g. mmc, ethmac + """ + return '' + peripherals_handlers = { 'uart': { 'handler': generate_peripheral, @@ -630,7 +637,7 @@ peripherals_handlers = { 'handler': generate_video_framebuffer, }, 'video_framebuffer_vtg': { - 'handler': lambda *args, **kwargs: "", # This is handled by generate_video_framebuffer + 'handler': handled_peripheral, # This is handled by generate_video_framebuffer }, 'leds': { 'handler': generate_leds, @@ -638,6 +645,19 @@ peripherals_handlers = { 'switches': { 'handler': generate_switches, }, + 'ethphy': { + 'handler': handled_peripheral # by generate_ethmac + }, + # handled by generate_mmc + 'sdblock2mem': { + 'handler': handled_peripheral + }, + 'sdmem2block': { + 'handler': handled_peripheral + }, + 'sdcore': { + 'handler': handled_peripheral + }, } From 65964692dd05b1ee0e441d8d77f0568492716786 Mon Sep 17 00:00:00 2001 From: Mateusz Karlic Date: Mon, 17 Oct 2022 08:16:32 +0200 Subject: [PATCH 07/12] json2renode: Add auto-align hint --- litex/tools/litex_json2renode.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/litex/tools/litex_json2renode.py b/litex/tools/litex_json2renode.py index ced32904a..1cfe82e3d 100755 --- a/litex/tools/litex_json2renode.py +++ b/litex/tools/litex_json2renode.py @@ -772,6 +772,8 @@ def filter_memory_regions(raw_regions, alignment=None, autoalign=[]): size_mismatch = r['size'] % alignment address_mismatch = r['base'] % alignment + def print_autoalign_hint(): + print('Hint: use "--auto-align {}" to force automatic alignement of the region'.format(r['name'])) if address_mismatch != 0: if r['name'] in autoalign: r['original_address'] = r['base'] @@ -779,6 +781,7 @@ def filter_memory_regions(raw_regions, alignment=None, autoalign=[]): print('Re-aligning `{}` memory region base address from {} to {} due to limitations in Renode'.format(r['name'], hex(r['original_address']), hex(r['base']))) else: print('Error: `{}` memory region base address ({}) is not aligned to {}. This configuration cannot be currently simulated in Renode'.format(r['name'], hex(r['size']), hex(alignment))) + print_autoalign_hint() sys.exit(1) if size_mismatch != 0: @@ -788,6 +791,7 @@ def filter_memory_regions(raw_regions, alignment=None, autoalign=[]): print('Extending `{}` memory region size from {} to {} due to limitations in Renode'.format(r['name'], hex(r['original_size']), hex(r['size']))) else: print('Error: `{}` memory region size ({}) is not aligned to {}. This configuration cannot be currently simulated in Renode'.format(r['name'], hex(r['size']), hex(alignment))) + print_autoalign_hint() sys.exit(1) if r['size'] == 0: From b4bddc68e758699d1da184b36b714e7c3625f5f3 Mon Sep 17 00:00:00 2001 From: Mateusz Karlic Date: Mon, 17 Oct 2022 08:43:52 +0200 Subject: [PATCH 08/12] json2renode: Add LiteX MMCM --- litex/tools/litex_json2renode.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/litex/tools/litex_json2renode.py b/litex/tools/litex_json2renode.py index 1cfe82e3d..0dafeeb16 100755 --- a/litex/tools/litex_json2renode.py +++ b/litex/tools/litex_json2renode.py @@ -645,6 +645,12 @@ peripherals_handlers = { 'switches': { 'handler': generate_switches, }, + 'mmcm': { + 'handler': generate_peripheral, + 'model': 'Miscellaneous.LiteX_MMCM', + 'model_CSR32': 'Miscellaneous.LiteX_MMCM_CSR32', + 'ignored_constants': ['lock_timeout', 'drdy_timeout'], + }, 'ethphy': { 'handler': handled_peripheral # by generate_ethmac }, From 4c959740ddf128645dcfb28421d75ae2ca77c6c2 Mon Sep 17 00:00:00 2001 From: Mateusz Karlic Date: Fri, 21 Oct 2022 09:50:51 +0200 Subject: [PATCH 09/12] json2renode: Use cpu_count as local variable --- litex/tools/litex_json2renode.py | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/litex/tools/litex_json2renode.py b/litex/tools/litex_json2renode.py index 0dafeeb16..488f9b2cb 100755 --- a/litex/tools/litex_json2renode.py +++ b/litex/tools/litex_json2renode.py @@ -20,8 +20,6 @@ import argparse # and should not be generated automatically non_generated_mem_regions = ['ethmac', 'csr'] -# let's just fail if we access this prematurely -number_of_cores = None def get_descriptor(csr, name, size=None): res = { 'base': csr['csr_bases'][name], 'constants': {} } @@ -207,10 +205,9 @@ def get_cpu_type(csr): return (kind, variant) def get_cpu_count(csr): - config_cpu_count = csr['constants']['config_cpu_count'] - return config_cpu_count + return csr['constants']['config_cpu_count'] -def generate_cpu(csr, time_provider): +def generate_cpu(csr, time_provider, number_of_cores): """ Generates definition of a CPU. Returns: @@ -424,7 +421,7 @@ mmc_controller: SD.LiteSDCard{} @ {{ return result -def generate_clint(clint, frequency): +def generate_clint(clint, frequency, number_of_cores): # TODO: this is configuration for VexRiscv - add support for other CPU types result = """ clint: IRQControllers.CoreLevelInterruptor @ {} @@ -441,7 +438,7 @@ clint: IRQControllers.CoreLevelInterruptor @ {} return result -def generate_plic(plic): +def generate_plic(plic, number_of_cores): # TODO: this is configuration for linux-on-litex-vexriscv - add support for other CPU types result = """ plic: IRQControllers.PlatformLevelInterruptController @ {} @@ -675,7 +672,7 @@ def generate_etherbone_bridge(name, address, port): """.format(name, hex(address), port) -def generate_repl(csr, etherbone_peripherals, autoalign): +def generate_repl(csr, etherbone_peripherals, autoalign, number_of_cores): """ Generates platform definition. Args: @@ -694,8 +691,6 @@ def generate_repl(csr, etherbone_peripherals, autoalign): peripherals and memory regions """ result = "" - global number_of_cores - number_of_cores = get_cpu_count(csr) # RISC-V CPU in Renode requires memory region size # to be a multiple of 4KB - this is a known limitation @@ -715,16 +710,16 @@ def generate_repl(csr, etherbone_peripherals, autoalign): time_provider = None if 'clint' in csr['memories']: - result += generate_clint(csr['memories']['clint'], csr['constants']['config_clock_frequency']) + result += generate_clint(csr['memories']['clint'], csr['constants']['config_clock_frequency'], number_of_cores) time_provider = 'clint' if 'plic' in csr['memories']: - result += generate_plic(csr['memories']['plic']) + result += generate_plic(csr['memories']['plic'], number_of_cores) if not time_provider and 'cpu' in csr['csr_bases']: time_provider = 'cpu_timer' - result += generate_cpu(csr, time_provider) + result += generate_cpu(csr, time_provider, number_of_cores) for name, address in csr['csr_bases'].items(): if name not in peripherals_handlers: @@ -838,7 +833,7 @@ def find_memory_region(memory_regions, address): return None -def generate_resc(csr, args, flash_binaries={}, tftp_binaries={}): +def generate_resc(csr, number_of_cores, args, flash_binaries={}, tftp_binaries={}): """ Generates platform definition. Args: @@ -1059,8 +1054,10 @@ def main(): etherbone_peripherals = check_etherbone_peripherals(args.etherbone_peripherals) + number_of_cores = get_cpu_count(csr) + if args.repl: - print_or_save(args.repl, generate_repl(csr, etherbone_peripherals, args.autoalign_memor_regions)) + print_or_save(args.repl, generate_repl(csr, etherbone_peripherals, args.autoalign_memor_regions, number_of_cores)) if args.resc: if not args.repl: @@ -1070,7 +1067,7 @@ def main(): flash_binaries = parse_flash_binaries(csr, args) tftp_binaries = check_tftp_binaries(args) - print_or_save(args.resc, generate_resc(csr, args, + print_or_save(args.resc, generate_resc(csr, number_of_cores, args, flash_binaries, tftp_binaries)) From 97772eb4bd0f6a07a5130a896e789f1151027589 Mon Sep 17 00:00:00 2001 From: Mateusz Karlic Date: Fri, 21 Oct 2022 14:14:23 +0200 Subject: [PATCH 10/12] json2renode: IRQ: Fallback to cpu0 if plic is unavailable --- litex/tools/litex_json2renode.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/litex/tools/litex_json2renode.py b/litex/tools/litex_json2renode.py index 488f9b2cb..e7aaaddea 100755 --- a/litex/tools/litex_json2renode.py +++ b/litex/tools/litex_json2renode.py @@ -20,6 +20,14 @@ import argparse # and should not be generated automatically non_generated_mem_regions = ['ethmac', 'csr'] +def get_soc_interrupt_parent(csr): + ''' + We assume that for multi-core setups plic will be used hence cpu0 is enough + ''' + if 'plic' in csr['memories']: + return 'plic' + else: + return 'cpu0' def get_descriptor(csr, name, size=None): res = { 'base': csr['csr_bases'][name], 'constants': {} } @@ -110,7 +118,8 @@ ethmac: Network.LiteX_Ethernet{} @ {{ interrupt_name = '{}_interrupt'.format(name) if interrupt_name in csr['constants']: - result += ' -> plic@{}\n'.format( + result += ' -> {}@{}\n'.format( + get_soc_interrupt_parent(csr), csr['constants'][interrupt_name]) result += """ @@ -306,7 +315,7 @@ def generate_peripheral(csr, name, **kwargs): for constant, val in peripheral['constants'].items(): if 'ignored_constants' not in kwargs or constant not in kwargs['ignored_constants']: if constant == 'interrupt': - result += ' -> plic@{}\n'.format(val) + result += ' -> {}@{}\n'.format(get_soc_interrupt_parent(csr), val) else: result += ' {}: {}\n'.format(constant, val) @@ -508,7 +517,7 @@ def generate_gpio_port(csr, name, **kwargs): ints = '' if 'interrupt' in kwargs: - ints += f' IRQ -> plic@{kwargs["interrupt"]}' + ints += f' IRQ -> {get_soc_interrupt_parent(csr)}@{kwargs["interrupt"]}' if 'connections' in kwargs: for irq, target in zip(kwargs['connections'], kwargs['connections_targets']): ints += f' {irq} -> {target}\n' From eccb26874edc04dfdeb2e1c980547dc21dc71dd7 Mon Sep 17 00:00:00 2001 From: Mateusz Karlic Date: Fri, 21 Oct 2022 14:36:59 +0200 Subject: [PATCH 11/12] json2renode: cpu: Extract minor common logic --- litex/tools/litex_json2renode.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/litex/tools/litex_json2renode.py b/litex/tools/litex_json2renode.py index e7aaaddea..034edc59a 100755 --- a/litex/tools/litex_json2renode.py +++ b/litex/tools/litex_json2renode.py @@ -241,10 +241,6 @@ CPU.VexRiscv @ sysbus cpu_string += """ cpuType: "rv32im" """ - if time_provider: - cpu_string += """ - timeProvider: {} -""".format(time_provider) elif kind == 'picorv32': cpu_string = """ @@ -271,10 +267,6 @@ CPU.CV32E40P @ sysbus cpu_string += """ cpuType: "rv32imc" """ - if time_provider: - cpu_string += """ - timeProvider: {} -""".format(time_provider) else: raise Exception('Unsupported cpu type: {}'.format(kind)) @@ -285,6 +277,8 @@ CPU.CV32E40P @ sysbus cpu{cpu_id}: {cpu_string.strip()} hartId: {cpu_id} """ + if time_provider: + result += f' timeProvider: {time_provider}\n' return result From cd90e2623a05a160075982fc31c24dd5000b973c Mon Sep 17 00:00:00 2001 From: Mateusz Karlic Date: Fri, 21 Oct 2022 15:51:20 +0200 Subject: [PATCH 12/12] json2renode: cpu: Overhaul generate_cpu --- litex/tools/litex_json2renode.py | 112 ++++++++++++++++++------------- 1 file changed, 66 insertions(+), 46 deletions(-) diff --git a/litex/tools/litex_json2renode.py b/litex/tools/litex_json2renode.py index 034edc59a..3cd37aa73 100755 --- a/litex/tools/litex_json2renode.py +++ b/litex/tools/litex_json2renode.py @@ -216,6 +216,50 @@ def get_cpu_type(csr): def get_cpu_count(csr): return csr['constants']['config_cpu_count'] +vexriscv_common_kind = { + 'name': 'VexRiscv', + 'variants': { + 'linux': { + 'properties': ['cpuType: "rv32ima"', 'privilegeArchitecture: PrivilegeArchitecture.Priv1_10'], + }, + 'i': { + 'properties': ['cpuType: "rv32i"'], + }, + 'im': { + 'properties': ['cpuType: "rv32im"'], + }, + 'ima': { + 'properties': ['cpuType: "rv32ima"'], + }, + 'imac': { + 'properties': ['cpuType: "rv32imac"'], + }, + 'others': { + 'properties': ['cpuType: "rv32im"'], + } + }, + 'supports_time_provider': True, +} +cpu_kinds = { + 'vexriscv': vexriscv_common_kind, + 'vexriscv_smp': vexriscv_common_kind, + 'picorv32': { + 'name': 'PicoRV32', + 'properties': ['cpuType: "rv32imc"'], + }, + 'minerva': { + 'name': 'Minerva', + }, + 'ibex': { + 'name': 'IbexRiscV32', + }, + 'cv32e40p': { + 'name': 'CV32E40P', + 'supports_time_provider': True, + 'properties': ['cpuType: "rv32imc"'], + } +} + def generate_cpu(csr, time_provider, number_of_cores): """ Generates definition of a CPU. @@ -224,60 +268,36 @@ def generate_cpu(csr, time_provider, number_of_cores): """ kind, variant = get_cpu_type(csr) - if kind == 'vexriscv' or kind == 'vexriscv_smp': - cpu_string = """ -CPU.VexRiscv @ sysbus -""" - if variant == 'linux': - cpu_string += """ - cpuType: "rv32ima" - privilegeArchitecture: PrivilegeArchitecture.Priv1_10 -""" - elif variant in ["i", "im", "ima", "imac"]: - cpu_string += """ - cpuType: "rv32{}" -""".format(variant) - else: - cpu_string += """ - cpuType: "rv32im" -""" + try: + cpu = cpu_kinds[kind] - elif kind == 'picorv32': - cpu_string = """ -CPU.PicoRV32 @ sysbus - cpuType: "rv32imc" -""" - elif kind == 'minerva': - cpu_string = """ -CPU.Minerva @ sysbus -""" - elif kind == 'ibex': - cpu_string = """ -CPU.IbexRiscV32 @ sysbus -""" - elif kind == 'cv32e40p': - cpu_string = """ -CPU.CV32E40P @ sysbus -""" - if variant == 'standard': - cpu_string += """ - cpuType: "rv32imc" -""" - else: - cpu_string += """ - cpuType: "rv32imc" -""" + cpu_string = f'{cpu["name"]} @ sysbus\n' + + def unpack_properties(prop_list): + return ''.join([f' {prop}\n' for prop in prop_list]) - else: - raise Exception('Unsupported cpu type: {}'.format(kind)) + if 'properties' in cpu: + cpu_string += unpack_properties(cpu["properties"]) + + if 'variants' in cpu: + variant = cpu['variants'].get(variant) + + if variant is None: + variant = cpu['variants'].get('others', []) + + if 'properties' in variant: + cpu_string += unpack_properties(variant["properties"]) + + except KeyError: + raise Exception(f'Unsupported cpu type: {kind}') result = '' for cpu_id in range(0, number_of_cores): result += f""" -cpu{cpu_id}: {cpu_string.strip()} +cpu{cpu_id}: CPU.{cpu_string.strip()} hartId: {cpu_id} """ - if time_provider: + if cpu.get('supports_time_provider', False): result += f' timeProvider: {time_provider}\n' return result