From ae69e38209391258fc0f7b5e1f9fae4b97d5b4be Mon Sep 17 00:00:00 2001 From: ishitani Date: Tue, 20 May 2025 14:01:50 +0900 Subject: [PATCH 1/2] rewrite with Veryl --- .gitignore | 7 + Veryl.toml | 19 + veryl/pzbcm_arbiter/pzbcm_arbiter.veryl | 126 ++++ veryl/pzbcm_arbiter/pzbcm_arbiter_pkg.veryl | 24 + .../pzbcm_round_robin_arbiter.veryl | 211 +++++++ veryl/pzbcm_sram/pzbcm_sram.veryl | 311 ++++++++++ veryl/pzbcm_sram/pzbcm_sram_fifo.veryl | 114 ++++ veryl/pzbcm_sram/pzbcm_sram_if.veryl | 82 +++ veryl/pzbcm_sram/pzbcm_sram_pkg.veryl | 61 ++ .../pzbcm_sram_wrapper_default.veryl | 65 ++ .../pzbcm_sram/pzbcm_sram_wrapper_proto.veryl | 20 + .../pzcorebus_common_pkg.veryl | 378 ++++++++++++ .../pzcorebus_id_assigner.veryl | 39 ++ veryl/pzcorebus_common/pzcorebus_if.veryl | 563 ++++++++++++++++++ veryl/pzcorebus_common/pzcorebus_pkg.veryl | 173 ++++++ .../pzcorebus_utils_pkg.veryl | 114 ++++ .../pzcorebus_csrbus_adapter.veryl | 523 ++++++++++++++++ .../pzcorebus_csrbus_adapter_buffer.veryl | 167 ++++++ .../pzcorebus_debug_mcmd_counter.veryl | 42 ++ .../pzcorebus_debug_mlengh_counter.veryl | 46 ++ .../pzcorebus_debug/pzcorebus_debug_pkg.veryl | 61 ++ .../pzcorebus_debug_sresp_counter.veryl | 45 ++ .../pzcorebus_downsizer.veryl | 69 +++ .../pzcorebus_downsizer_request_path.veryl | 122 ++++ .../pzcorebus_downsizer_response_path.veryl | 137 +++++ .../pzcorebus_dummy_master.veryl | 18 + .../pzcorebus_dummy_slave.veryl | 257 ++++++++ veryl/pzcorebus_fifo/pzcorebus_fifo.veryl | 217 +++++++ .../pzcorebus_fifo/pzcorebus_mcmd_fifo.veryl | 86 +++ .../pzcorebus_fifo/pzcorebus_mreq_fifo.veryl | 151 +++++ .../pzcorebus_fifo/pzcorebus_sresp_fifo.veryl | 86 +++ .../pzcorebus_mreq_aligner.veryl | 57 ++ .../pzcorebus_mreq_aligner_core.veryl | 186 ++++++ .../pzcorebus_mreq_mdata_fifo.veryl | 55 ++ .../pzcorebus_mreq_packer.veryl | 173 ++++++ .../pzcorebus_mreq_mux.veryl | 79 +++ .../pzcorebus_sresp_demux.veryl | 41 ++ .../pzcorebus_sresp_mux.veryl | 44 ++ veryl/pzcorebus_slicer/pzcorebus_slicer.veryl | 128 ++++ .../pzcorebus_1_to_m_switch.veryl | 100 ++++ .../pzcorebus_m_to_1_switch.veryl | 121 ++++ .../pzcorebus_mreq_1_to_m_switch.veryl | 227 +++++++ .../pzcorebus_mreq_m_to_1_switch.veryl | 253 ++++++++ .../pzcorebus_sresp_1_to_m_switch.veryl | 121 ++++ .../pzcorebus_sresp_m_to_1_switch.veryl | 104 ++++ veryl/pzhsbus_common/pzhsbus_if.veryl | 31 + veryl/pzhsbus_fifo/pzhsbus_fifo.veryl | 61 ++ veryl/pzhsbus_selector/pzhsbus_demux.veryl | 49 ++ veryl/pzhsbus_selector/pzhsbus_mux.veryl | 53 ++ veryl/pzhsbus_slicer/pzhsbus_slicer.veryl | 35 ++ 50 files changed, 6252 insertions(+) create mode 100644 Veryl.toml create mode 100644 veryl/pzbcm_arbiter/pzbcm_arbiter.veryl create mode 100644 veryl/pzbcm_arbiter/pzbcm_arbiter_pkg.veryl create mode 100644 veryl/pzbcm_arbiter/pzbcm_round_robin_arbiter.veryl create mode 100644 veryl/pzbcm_sram/pzbcm_sram.veryl create mode 100644 veryl/pzbcm_sram/pzbcm_sram_fifo.veryl create mode 100644 veryl/pzbcm_sram/pzbcm_sram_if.veryl create mode 100644 veryl/pzbcm_sram/pzbcm_sram_pkg.veryl create mode 100644 veryl/pzbcm_sram/pzbcm_sram_wrapper_default.veryl create mode 100644 veryl/pzbcm_sram/pzbcm_sram_wrapper_proto.veryl create mode 100644 veryl/pzcorebus_common/pzcorebus_common_pkg.veryl create mode 100644 veryl/pzcorebus_common/pzcorebus_id_assigner.veryl create mode 100644 veryl/pzcorebus_common/pzcorebus_if.veryl create mode 100644 veryl/pzcorebus_common/pzcorebus_pkg.veryl create mode 100644 veryl/pzcorebus_common/pzcorebus_utils_pkg.veryl create mode 100644 veryl/pzcorebus_csrbus_adapter/pzcorebus_csrbus_adapter.veryl create mode 100644 veryl/pzcorebus_csrbus_adapter/pzcorebus_csrbus_adapter_buffer.veryl create mode 100644 veryl/pzcorebus_debug/pzcorebus_debug_mcmd_counter.veryl create mode 100644 veryl/pzcorebus_debug/pzcorebus_debug_mlengh_counter.veryl create mode 100644 veryl/pzcorebus_debug/pzcorebus_debug_pkg.veryl create mode 100644 veryl/pzcorebus_debug/pzcorebus_debug_sresp_counter.veryl create mode 100644 veryl/pzcorebus_downsizer/pzcorebus_downsizer.veryl create mode 100644 veryl/pzcorebus_downsizer/pzcorebus_downsizer_request_path.veryl create mode 100644 veryl/pzcorebus_downsizer/pzcorebus_downsizer_response_path.veryl create mode 100644 veryl/pzcorebus_dummy/pzcorebus_dummy_master.veryl create mode 100644 veryl/pzcorebus_dummy/pzcorebus_dummy_slave.veryl create mode 100644 veryl/pzcorebus_fifo/pzcorebus_fifo.veryl create mode 100644 veryl/pzcorebus_fifo/pzcorebus_mcmd_fifo.veryl create mode 100644 veryl/pzcorebus_fifo/pzcorebus_mreq_fifo.veryl create mode 100644 veryl/pzcorebus_fifo/pzcorebus_sresp_fifo.veryl create mode 100644 veryl/pzcorebus_mreq_aligner/pzcorebus_mreq_aligner.veryl create mode 100644 veryl/pzcorebus_mreq_aligner/pzcorebus_mreq_aligner_core.veryl create mode 100644 veryl/pzcorebus_mreq_packer/pzcorebus_mreq_mdata_fifo.veryl create mode 100644 veryl/pzcorebus_mreq_packer/pzcorebus_mreq_packer.veryl create mode 100644 veryl/pzcorebus_selector/pzcorebus_mreq_mux.veryl create mode 100644 veryl/pzcorebus_selector/pzcorebus_sresp_demux.veryl create mode 100644 veryl/pzcorebus_selector/pzcorebus_sresp_mux.veryl create mode 100644 veryl/pzcorebus_slicer/pzcorebus_slicer.veryl create mode 100644 veryl/pzcorebus_switch/pzcorebus_1_to_m_switch.veryl create mode 100644 veryl/pzcorebus_switch/pzcorebus_m_to_1_switch.veryl create mode 100644 veryl/pzcorebus_switch/pzcorebus_mreq_1_to_m_switch.veryl create mode 100644 veryl/pzcorebus_switch/pzcorebus_mreq_m_to_1_switch.veryl create mode 100644 veryl/pzcorebus_switch/pzcorebus_sresp_1_to_m_switch.veryl create mode 100644 veryl/pzcorebus_switch/pzcorebus_sresp_m_to_1_switch.veryl create mode 100644 veryl/pzhsbus_common/pzhsbus_if.veryl create mode 100644 veryl/pzhsbus_fifo/pzhsbus_fifo.veryl create mode 100644 veryl/pzhsbus_selector/pzhsbus_demux.veryl create mode 100644 veryl/pzhsbus_selector/pzhsbus_mux.veryl create mode 100644 veryl/pzhsbus_slicer/pzhsbus_slicer.veryl diff --git a/.gitignore b/.gitignore index bccc930..3880ef7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,9 @@ *.f Gemfile.lock + +# Veryl +Veryl.lock +/.build +/dependencies +/generated +/map diff --git a/Veryl.toml b/Veryl.toml new file mode 100644 index 0000000..03f25bf --- /dev/null +++ b/Veryl.toml @@ -0,0 +1,19 @@ +[project] +name = "pzbcm" +version = "0.1.0" +authors = ["Taichi Ishitani "] +license = "Apache-2.0" +repository = "https://github.com/pezy-computing/pzbcm" + +[build] +clock_type = "posedge" +reset_type = "async_low" +filelist_type = "flgen" +target = {type = "directory", path = "generated"} +sourcemap_target = {type = "directory", path = "map"} +omit_project_prefix = true +reset_low_suffix = "_n" +hashed_mangled_name = true + +[format] +indent_width = 2 diff --git a/veryl/pzbcm_arbiter/pzbcm_arbiter.veryl b/veryl/pzbcm_arbiter/pzbcm_arbiter.veryl new file mode 100644 index 0000000..c90c03e --- /dev/null +++ b/veryl/pzbcm_arbiter/pzbcm_arbiter.veryl @@ -0,0 +1,126 @@ +//======================================== +// +// Copyright (c) 2026 PEZY Computing, K.K. +// +//======================================== +pub module pzbcm_arbiter #( + param REQUESTS : u32 = 2 , + param ONEHOT_GRANT : bbool = true , + param KEEP_RESULT : bbool = true , + param GRANT_WIDTH : u32 = calc_grant_width(REQUESTS, ONEHOT_GRANT), + param FREE_WIDTH : u32 = REQUESTS , + param PRIORITY_ENABLE: bbool = false , + param PRIORITY_WIDTH : u32 = 1 , + param WEIGHT_ENABLE : bbool = false , + param WEIGHT_WIDTH : u32 = 1 , + param INITIAL_WEIGHT : bit = '1 , +)( + i_clk : input clock , + i_rst : input reset , + i_kind : input pzbcm_arbiter_kind = pzbcm_arbiter_kind::ROUND_ROBIN, + i_init : input logic = false , + i_priority : input logic = '0 , + i_weight_valid: input logic = false , + i_weight : input logic = '0 , + i_request : input logic , + o_grant : output logic , + i_free : input logic , +) { + import pzbcm_arbiter_pkg::*; + + if REQUESTS >= 2 :g { + var request: logic ; + var grant : logic; + var busy : logic ; + + always_comb { + request = if !busy ? i_request : '0; + } + + inst u_round_robin_arbiter: pzbcm_round_robin_arbiter #( + REQUESTS : REQUESTS , + ONEHOT_GRANT : ONEHOT_GRANT , + PRIORITY_ENABLE: PRIORITY_ENABLE, + PRIORITY_WIDTH : PRIORITY_WIDTH , + WEIGHT_ENABLE : WEIGHT_ENABLE , + WEIGHT_WIDTH : WEIGHT_WIDTH , + INITIAL_WEIGHT : INITIAL_WEIGHT , + )( + i_clk : i_clk , + i_rst : i_rst , + i_kind : i_kind , + i_init : i_init , + i_priority : i_priority , + i_weight_valid: i_weight_valid, + i_weight : i_weight , + i_request : request , + o_grant : grant , + ); + + if KEEP_RESULT :g_grant { + var free : logic ; + var current_grant: logic; + var grant_latched: logic; + + always_comb { + o_grant = current_grant; + } + + always_comb { + if !busy { + current_grant = grant; + } else { + current_grant = grant_latched; + } + } + + always_ff { + if_reset { + busy = false; + } else if free { + busy = false; + } else if request != '0 { + busy = true; + } + } + + always_ff { + if_reset { + grant_latched = 0 as GRANT_WIDTH; + } else if request != '0 { + grant_latched = grant; + } + } + + if FREE_WIDTH == 1 :g_free { + always_comb { + free = i_free; + } + } else if ONEHOT_GRANT { + always_comb { + free = (i_free & current_grant) != '0; + } + } else { + always_comb { + free = i_free[current_grant]; + } + } + } else { + always_comb { + o_grant = grant; + } + + always_comb { + busy = false; + } + } + } else if ONEHOT_GRANT { + always_comb { + o_grant = '1; + } + } else { + always_comb { + o_grant = 0 as GRANT_WIDTH; + } + } +} diff --git a/veryl/pzbcm_arbiter/pzbcm_arbiter_pkg.veryl b/veryl/pzbcm_arbiter/pzbcm_arbiter_pkg.veryl new file mode 100644 index 0000000..cbb1396 --- /dev/null +++ b/veryl/pzbcm_arbiter/pzbcm_arbiter_pkg.veryl @@ -0,0 +1,24 @@ +//======================================== +// +// Copyright (c) 2026 PEZY Computing, K.K. +// +//======================================== +pub package pzbcm_arbiter_pkg { + enum pzbcm_arbiter_kind { + FIXED_PRIORITY, + ROUND_ROBIN , + } + + function calc_grant_width( + requests : input u32 , + onehot_grant: input bbool, + ) -> u32 { + if requests == 1 { + return 1; + } else if onehot_grant { + return requests; + } else { + return $clog2(requests); + } + } +} diff --git a/veryl/pzbcm_arbiter/pzbcm_round_robin_arbiter.veryl b/veryl/pzbcm_arbiter/pzbcm_round_robin_arbiter.veryl new file mode 100644 index 0000000..111be10 --- /dev/null +++ b/veryl/pzbcm_arbiter/pzbcm_round_robin_arbiter.veryl @@ -0,0 +1,211 @@ +//======================================== +// +// Copyright (c) 2026 PEZY Computing, K.K. +// +//======================================== +pub module pzbcm_round_robin_arbiter #( + param REQUESTS : u32 = 4 , + param ONEHOT_GRANT : bbool = true , + param GRANT_WIDTH : u32 = calc_grant_width(REQUESTS, ONEHOT_GRANT), + param PRIORITY_ENABLE: bbool = false , + param PRIORITY_WIDTH : u32 = 1 , + param WEIGHT_ENABLE : bbool = false , + param WEIGHT_WIDTH : u32 = 1 , + param INITIAL_WEIGHT : bit = '1 , +)( + i_clk : input clock , + i_rst : input reset , + i_kind : input pzbcm_arbiter_kind = pzbcm_arbiter_kind::ROUND_ROBIN, + i_init : input logic = false , + i_priority : input logic = '0 , + i_weight_valid: input logic = false , + i_weight : input logic = '0 , + i_request : input logic , + o_grant : output logic , +) { + import pzbcm_arbiter_pkg::*; + + const COMPARE_WIDTH: u32 = 2 + (if WEIGHT_ENABLE ? 1 : 0) + (if PRIORITY_ENABLE ? PRIORITY_WIDTH : 0); + const INDEX_WIDTH : u32 = $clog2(REQUESTS); + const WEIGHT_LSB : u32 = 1; + const PRIORITY_LSB : u32 = WEIGHT_LSB + (if WEIGHT_ENABLE ? 1 : 0); + const REQUEST_LSB : u32 = PRIORITY_LSB + (if PRIORITY_ENABLE ? PRIORITY_WIDTH : 0); + + struct pzbcm_arbiter_compare_data { + index: logic , + value: logic, + } + + struct pzbcm_arbiter_compare_result { + location: logic , + result : pzbcm_arbiter_compare_data, + } + + var current_grant : logic ; + var use_round_robin: logic ; + var weight : logic ; + var compare_data : pzbcm_arbiter_compare_data; + var compare_result : pzbcm_arbiter_compare_result ; + +//-------------------------------------------------------------- +// Arbiter +//-------------------------------------------------------------- + if ONEHOT_GRANT :g_result { + always_comb { + o_grant = compare_result.location; + } + } else { + always_comb { + o_grant = compare_result.result.index; + } + } + + always_comb { + use_round_robin = i_kind == pzbcm_arbiter_kind::ROUND_ROBIN; + } + + always_comb { + for i in 0..REQUESTS { + compare_data[i].index = i as INDEX_WIDTH; + compare_data[i].value[0] = use_round_robin && ((i as INDEX_WIDTH) >: current_grant); + compare_data[i].value[REQUEST_LSB] = i_request[i]; + if WEIGHT_ENABLE { + compare_data[i].value[WEIGHT_LSB] = weight[i] >= (1 as WEIGHT_WIDTH); + } + if PRIORITY_ENABLE { + compare_data[i].value[PRIORITY_LSB+:PRIORITY_WIDTH] = i_priority[i]; + } + } + + compare_result = find_max(compare_data); + } + + always_ff { + if_reset { + current_grant = 0 as INDEX_WIDTH; + } else if i_init || !use_round_robin { + current_grant = 0 as INDEX_WIDTH; + } else if i_request != '0 { + current_grant = compare_result.result.index; + } + } + + function find_max( + compare_data: input pzbcm_arbiter_compare_data, + ) -> pzbcm_arbiter_compare_result { + const DEPTH: u32 = $clog2(REQUESTS); + + var stride : u32 ; + var current_n : u32 ; + var next_n : u32 ; + var current_location: logic ; + var next_location : logic ; + var current_data : pzbcm_arbiter_compare_data; + var next_data : pzbcm_arbiter_compare_data; + var result : pzbcm_arbiter_compare_result ; + + next_n = REQUESTS; + next_location = '1; + next_data = compare_data; + for i in 0..DEPTH { + current_n = next_n; + current_location = next_location; + current_data = next_data; + + next_n = (current_n / 2) + (current_n % 2); + stride = 2**i; + + for j in 0..next_n { + var compare_result: logic<2>; + + if (j + 1) == next_n && (current_n % 2) == 1 { + compare_result = 2'b01; + } else if current_data[2*j+0].value >= current_data[2*j+1].value { + compare_result = 2'b01; + } else { + compare_result = 2'b10; + } + + if compare_result[0] { + next_data[j] = current_data[2*j+0]; + } else { + next_data[j] = current_data[2*j+1]; + } + + for k in 0..(2 * stride) { + let index: u32 = 2 * stride * j + k; + if index <: REQUESTS { + next_location[index] = compare_result[k/stride] && current_location[index]; + } + } + } + } + + result.result = next_data; + result.location = next_location; + return result; + } + +//-------------------------------------------------------------- +// Weight +//-------------------------------------------------------------- + if WEIGHT_ENABLE >= 1 :g_weight { + const RESET_COUNT_WIDTH: u32 = $clog2(REQUESTS); + const MAX_RESET_COUNT : u32 = REQUESTS - 1; + + var weight_eq_0 : logic ; + var weight_eq_0_grant: logic ; + var reset_count : logic; + var reset_weight : logic ; + + always_comb { + reset_weight = + i_init + || !use_round_robin + || weight_eq_0_grant != '0 && reset_count == (MAX_RESET_COUNT as RESET_COUNT_WIDTH) + || weight_eq_0 == '1; + } + + always_ff { + if_reset { + reset_count = 0 as RESET_COUNT_WIDTH; + } else if reset_weight { + reset_count = 0 as RESET_COUNT_WIDTH; + } else if weight_eq_0_grant != '0 { + reset_count += 1 as RESET_COUNT_WIDTH; + } + } + + for i in 0..REQUESTS :g { + var grant: logic; + var eq_0 : logic; + var eq_1 : logic; + + always_comb { + grant = i_request[i] && compare_result.location[i]; + eq_0 = weight[i] == (0 as WEIGHT_WIDTH); + eq_1 = weight[i] == (1 as WEIGHT_WIDTH); + weight_eq_0 = eq_0 || eq_1 && grant; + weight_eq_0_grant = grant && eq_0; + } + + always_ff { + if_reset { + weight[i] = INITIAL_WEIGHT[i]; + } else if reset_weight { + if i_weight_valid { + weight[i] = i_weight[i]; + } else { + weight[i] = INITIAL_WEIGHT[i]; + } + } else if grant && !eq_0 { + weight[i] -= (1 as WEIGHT_WIDTH); + } + } + } + } else { + always_comb { + weight = '0; + } + } +} diff --git a/veryl/pzbcm_sram/pzbcm_sram.veryl b/veryl/pzbcm_sram/pzbcm_sram.veryl new file mode 100644 index 0000000..c6cb828 --- /dev/null +++ b/veryl/pzbcm_sram/pzbcm_sram.veryl @@ -0,0 +1,311 @@ +//======================================== +// +// Copyright (c) 2025 PEZY Computing, K.K. +// +//======================================== +pub module pzbcm_sram::#( + param OUTPUT_FIFO : bbool = true, + param WRITE_FIRST : bbool = true, + param RESET_DATA_PATH: bbool = true, +)( + i_clk : input clock , + i_rst : input reset , + i_clear : input logic , + i_sram_config: input PKG::SRAM_CONFIG_TYPE , + port_if : modport pzbcm_sram_if::::sram, +) { + import PKG::*; + + var write_ready : logic; + var write_enable : logic; + var read_ready : logic; + var read_enable : logic; + var read_enable_delay: logic; + var read_data : logic; + var read_data_valid : logic; + var read_info : READ_INFO_TYPE; + var read_busy : logic; + var ram_read_data : logic; + var fifo_ready : logic; + +//-------------------------------------------------------------- +// SRAM instance +//-------------------------------------------------------------- + always_comb { + port_if.write_ready = write_ready != '0; + port_if.read_ready = read_ready != '0; + } + + for i in 0..BANKS :g_bank { + var match_write : logic; + var write_pointer: logic; + var match_read : logic; + var read_pointer : logic; + + always_comb { + match_write = match_bank(i, port_if.write_pointer); + write_pointer = get_ram_pointer(port_if.write_pointer); + match_read = match_bank(i, port_if.read_pointer); + read_pointer = get_ram_pointer(port_if.read_pointer); + + if !SINGLE_PORT { + write_ready[i] = match_write; + write_enable[i] = port_if.write_valid && write_ready[i]; + read_ready[i] = match_read && fifo_ready; + read_enable[i] = port_if.read_valid && read_ready[i]; + } else if WRITE_FIRST { + write_ready[i] = match_write; + write_enable[i] = port_if.write_valid && write_ready[i]; + read_ready[i] = match_read && fifo_ready && (!write_enable[i]); + read_enable[i] = port_if.read_valid && read_ready[i]; + } else { + read_ready[i] = match_read && fifo_ready; + read_enable[i] = port_if.read_valid && read_ready[i]; + write_ready[i] = match_write && (!read_enable[i]); + write_enable[i] = port_if.write_valid && write_ready[i]; + } + } + + if SINGLE_PORT :g { + var enable : logic<1>; + var write : logic; + var ram_pointer: logic<1, RAM_POINTER_WIDTH>; + + always_comb { + enable[0] = write_enable[i] || read_enable[i]; + if write_enable[i] { + write = '1; + ram_pointer[0] = write_pointer; + } else { + write = '0; + ram_pointer[0] = read_pointer; + } + } + + inst u_sram_wrapper: SRAM_WRAPPER #( + WORDS : RAM_WORDS , + DATA_WIDTH : DATA_WIDTH , + POINTER_WIDTH : RAM_POINTER_WIDTH, + N_PORT : 1 , + SRAM_CONFIG_TYPE: SRAM_CONFIG_TYPE , + )( + i_clk : i_clk , + i_enable : enable , + i_pointer: ram_pointer , + i_write : write , + i_data : port_if.write_data, + o_data : read_data[i] , + i_config : i_sram_config , + ); + } else { + var enable : logic<2> ; + var ram_pointer: logic<2, RAM_POINTER_WIDTH>; + + always_comb { + enable[0] = write_enable[i]; + ram_pointer[0] = write_pointer; + enable[1] = read_enable[i]; + ram_pointer[1] = read_pointer; + } + + inst u_sram_wrapper: SRAM_WRAPPER #( + DATA_WIDTH : DATA_WIDTH , + POINTER_WIDTH : RAM_POINTER_WIDTH, + N_PORT : 2 , + SRAM_CONFIG_TYPE: SRAM_CONFIG_TYPE , + )( + i_clk : i_clk , + i_enable : enable , + i_pointer: ram_pointer , + i_write : '0 , + i_data : port_if.write_data, + o_data : read_data[i] , + i_config : i_sram_config , + ); + } + } + + function get_ram_pointer_map() -> bit { + var map : bit; + var bank_lsb : u16; + var bank_msb : u16; + var ram_pointer_pos: u16; + + if BANKS >= 2 { + bank_lsb = BANK_LSB; + bank_msb = bank_lsb - BANK_WIDTH - 1; + } else { + bank_lsb = 0; + bank_msb = 0; + } + + ram_pointer_pos = 0; + for i in 0..POINTER_WIDTH { + if (BANKS == 1) || ((i <: bank_lsb) || (i >: bank_msb)) { + map[ram_pointer_pos] = i; + ram_pointer_pos += 1; + } + } + + return map; + } + + const POINTER_MAP: bit = get_ram_pointer_map(); + + function get_ram_pointer( + pointer: input logic + ) -> logic { + if BANKS == 1 { + return pointer; + } else if BANK_LSB == 0 { + return (pointer >> BANK_WIDTH) as RAM_POINTER_WIDTH; + } else { + var ram_pointer: logic; + for i in 0..RAM_POINTER_WIDTH { + ram_pointer[i] = pointer[POINTER_MAP[i]]; + } + + return ram_pointer; + } + } + + function match_bank( + bank_index: input u16 , + pointer : input logic, + ) -> logic { + if BANKS == 1 { + return true; + } else { + let bank: logic = pointer[BANK_LSB+:BANK_WIDTH]; + return bank == (bank_index as BANK_WIDTH); + } + } + +//-------------------------------------------------------------- +// Read Data +//-------------------------------------------------------------- + always_comb { + port_if.read_busy = read_busy; + } + + always_comb { + read_busy = read_enable_delay != '0; + read_data_valid = read_enable_delay[READ_LATENCY - 1]; + } + + always_ff { + if_reset { + read_enable_delay = '0; + } else if i_clear { + read_enable_delay = '0; + } else { + for i in 0..READ_LATENCY { + if i == 0 { + read_enable_delay[i] = read_enable; + } else { + read_enable_delay[i] = read_enable_delay[i - 1]; + } + } + } + } + + if READ_INFO :g_read_info { + inst u_read_info_delay: $std::delay #( + DELAY: READ_LATENCY , + TYPE : READ_INFO_TYPE, + ) ( + i_clk: i_clk , + i_rst: i_rst , + i_d : port_if.read_info, + o_d : read_info , + ); + } else { + always_comb { + read_info = 0 as READ_INFO_TYPE; + } + } + + if BANKS == 1 :g_ram_read_data { + always_comb { + ram_read_data = read_data[0]; + } + } else { + inst u_read_data_mux: $std::mux #( + WIDTH : DATA_WIDTH , + ENTRIES: BANKS , + KIND : $std::selector_pkg::selector_kind::ONEHOT, + )( + i_select: read_data_valid, + i_data : read_data , + o_data : ram_read_data , + ); + } + +//-------------------------------------------------------------- +// Output FIFO +//-------------------------------------------------------------- + if OUTPUT_FIFO :g_output_fifo { + const FIFO_DATA_WIDTH: u16 = DATA_WIDTH + (if READ_INFO ? $bits(READ_INFO_TYPE) : 0); + const FIFO_DEPTH : u16 = READ_LATENCY + 2; + + var empty : logic; + var almost_full: logic; + var full : logic; + var push : logic; + var push_data : logic; + var pop : logic; + var pop_data : logic; + + always_comb { + port_if.fifo_empty = empty; + port_if.fifo_almost_full = almost_full; + port_if.fifo_full = full; + } + + always_comb { + fifo_ready = (!almost_full) || ((!read_busy) && (!full)); + } + + always_comb { + push = read_data_valid != '0; + push_data = {read_info, ram_read_data} as FIFO_DATA_WIDTH; + } + + always_comb { + pop = port_if.read_data_ready; + port_if.read_data_valid = !empty; + port_if.read_data = pop_data as pzbcm_sram_read_data; + } + + inst u_read_data_fifo: $std::fifo #( + WIDTH : FIFO_DATA_WIDTH, + DEPTH : FIFO_DEPTH , + THRESHOLD : 2 , + RESET_DATA_FF : RESET_DATA_PATH, + )( + i_clk : i_clk , + i_rst : i_rst , + i_clear : i_clear , + o_empty : empty , + o_almost_full: almost_full, + o_full : full , + o_word_count : _ , + i_push : push , + i_data : push_data , + i_pop : pop , + o_data : pop_data , + ); + } else { + always_comb { + fifo_ready = '1; + } + + always_comb { + port_if.fifo_empty = '1; + port_if.fifo_almost_full = '0; + port_if.fifo_full = '0; + port_if.read_data_valid = read_data_valid; + port_if.read_data = pzbcm_sram_read_data'{ data: ram_read_data, info: read_info }; + } + } +} diff --git a/veryl/pzbcm_sram/pzbcm_sram_fifo.veryl b/veryl/pzbcm_sram/pzbcm_sram_fifo.veryl new file mode 100644 index 0000000..8e3a50d --- /dev/null +++ b/veryl/pzbcm_sram/pzbcm_sram_fifo.veryl @@ -0,0 +1,114 @@ +//======================================== +// +// Copyright (c) 2025 PEZY Computing, K.K. +// +//======================================== +pub module pzbcm_sram_fifo:: #( + param TYPE : type = logic, + param THRESHOLD : u16 = PKG::WORDS , + param RESET_DATA_PATH: bbool = true , +)( + i_clk : input clock , + i_rst : input reset , + i_clear : input logic , + i_sram_config : input PKG::SRAM_CONFIG_TYPE, + o_empty : output logic , + o_completely_empty: output logic , + o_almost_full : output logic , + o_full : output logic , + o_completely_full : output logic , + i_push : input logic , + i_data : input TYPE , + i_pop : input logic , + o_data : output TYPE , +) { + embed (inline) sv {{{ + if ($bits(TYPE) != \{ PKG::DATA_WIDTH \}) begin : g_width_mismatch + $error("data width mismatch"); + end + }}} + + var empty : logic; + var almost_full: logic; + var full : logic; + var write_ack : logic; + var read_ack : logic; + var wp : logic; + var rp : logic; + + inst sram_if: pzbcm_sram_if::; + + always_comb { + o_empty = sram_if.fifo_empty; + o_completely_empty = sram_if.fifo_empty && empty && (!sram_if.read_busy); + o_almost_full = almost_full; + o_full = full; + o_completely_full = full && sram_if.fifo_full; + } + +//-------------------------------------------------------------- +// FIFO controller +//-------------------------------------------------------------- + always_comb { + write_ack = sram_if.write_ack(); + read_ack = sram_if.read_ack(); + } + + inst u_controller: $std::fifo_controller #( + TYPE : logic , + DEPTH : PKG::WORDS , + THRESHOLD : THRESHOLD , + FLAG_FF_OUT : true , + DATA_FF_OUT : false , + PUSH_ON_CLEAR : false , + RAM_WORDS : PKG::WORDS , + RAM_POINTER_WIDTH: PKG::POINTER_WIDTH, + MATCH_COUNT_WIDTH: 0 , + )( + i_clk : i_clk , + i_rst : i_rst , + i_clear : i_clear , + o_empty : empty , + o_almost_full : almost_full, + o_full : full , + o_word_count : _ , + i_push : write_ack , + i_data : '0 , + i_pop : read_ack , + o_write_pointer: wp , + o_write_to_ff : _ , + o_write_to_ram : _ , + o_read_pointer : rp , + o_read_from_ram: _ , + ); + +//-------------------------------------------------------------- +// SRAM +//-------------------------------------------------------------- + always_comb { + sram_if.write_valid = i_push && (!full); + sram_if.write_pointer = wp; + sram_if.write_data = i_data; + } + + always_comb { + sram_if.read_valid = !empty; + sram_if.read_pointer = rp; + sram_if.read_info = '0; + } + + always_comb { + sram_if.read_data_ready = i_pop; + o_data = sram_if.read_data.data as TYPE; + } + + inst u_sram: pzbcm_sram:: #( + OUTPUT_FIFO: true, + )( + i_clk : i_clk , + i_rst : i_rst , + i_clear : i_clear , + i_sram_config: i_sram_config, + port_if : sram_if , + ); +} diff --git a/veryl/pzbcm_sram/pzbcm_sram_if.veryl b/veryl/pzbcm_sram/pzbcm_sram_if.veryl new file mode 100644 index 0000000..b3f02ad --- /dev/null +++ b/veryl/pzbcm_sram/pzbcm_sram_if.veryl @@ -0,0 +1,82 @@ +//======================================== +// +// Copyright (c) 2025 PEZY Computing, K.K. +// +//======================================== +pub interface pzbcm_sram_if:: { + var write_ready : logic ; + var write_valid : logic ; + var write_pointer : logic; + var write_data : logic ; + var read_ready : logic ; + var read_valid : logic ; + var read_pointer : logic; + var read_info : PKG::READ_INFO_TYPE ; + var read_data_ready : logic ; + var read_data_valid : logic ; + var read_data : PKG::pzbcm_sram_read_data; + var read_busy : logic ; + var fifo_empty : logic ; + var fifo_almost_full: logic ; + var fifo_full : logic ; + + function write_ack() -> logic { + return write_ready && write_valid; + } + + function read_ack() -> logic { + return read_ready && read_valid; + } + + function read_data_ack() -> logic { + return read_data_ready && read_data_valid; + } + + modport write_port { + write_ready : input , + write_valid : output, + write_pointer: output, + write_data : output, + write_ack : import, + } + + modport read_port { + read_ready : input , + read_valid : output, + read_pointer : output, + read_info : output, + read_data_ready: output, + read_data_valid: input , + read_data : input , + read_ack : import, + read_data_ack : import, + } + + modport sram { + write_ready : output, + write_valid : input , + write_pointer : input , + write_data : input , + read_ready : output, + read_valid : input , + read_pointer : input , + read_info : input , + read_data_ready : input , + read_data_valid : output, + read_data : output, + read_busy : output, + fifo_empty : output, + fifo_almost_full: output, + fifo_full : output, + write_ack : import, + read_ack : import, + read_data_ack : import, + } + + modport monitor { + write_ack : import, + read_ack : import, + read_data_ack: import, + ..input + } +} diff --git a/veryl/pzbcm_sram/pzbcm_sram_pkg.veryl b/veryl/pzbcm_sram/pzbcm_sram_pkg.veryl new file mode 100644 index 0000000..ef053b8 --- /dev/null +++ b/veryl/pzbcm_sram/pzbcm_sram_pkg.veryl @@ -0,0 +1,61 @@ +//======================================== +// +// Copyright (c) 2025 PEZY Computing, K.K. +// +//======================================== +pub proto package pzbcm_sram_proto_pkg { + const WORDS : u16 ; + const DATA_WIDTH : u16 ; + const BANKS : u16 ; + const BANK_LSB : u16 ; + const SINGLE_PORT : bbool; + const READ_LATENCY : u16 ; + const SRAM_CONFIG_TYPE : type ; + const READ_INFO : bbool; + const READ_INFO_TYPE : type ; + const POINTER_WIDTH : u16 ; + const RAM_WORDS : u16 ; + const RAM_POINTER_WIDTH: u16 ; + const BANK_WIDTH : u16 ; + + alias module SRAM_WRAPPER: pzbcm_sram_wrapper_proto; + + struct pzbcm_sram_read_data { + info: READ_INFO_TYPE , + data: logic, + } +} + +pub package pzbcm_sram_pkg::< + words : u16 , + data_width : u16 , + banks : u16 = 1 , + bank_lsb : u16 = 0 , + single_port : bbool = true , + read_latency : u16 = 1 , + sram_config_type: type = lbool , + read_info : bbool = false , + read_info_type : type = lbool , + sram_wrapper : pzbcm_sram_wrapper_proto = pzbcm_sram_wrapper_default, +> for pzbcm_sram_proto_pkg { + const WORDS : u16 = words ; + const DATA_WIDTH : u16 = data_width ; + const BANKS : u16 = banks ; + const BANK_LSB : u16 = bank_lsb ; + const SINGLE_PORT : bbool = single_port ; + const READ_LATENCY : u16 = read_latency ; + const SRAM_CONFIG_TYPE : type = sram_config_type ; + const READ_INFO : bbool = read_info ; + const READ_INFO_TYPE : type = read_info_type ; + const POINTER_WIDTH : u16 = $clog2(WORDS) ; + const RAM_WORDS : u16 = WORDS / BANKS ; + const RAM_POINTER_WIDTH: u16 = $clog2(RAM_WORDS); + const BANK_WIDTH : u16 = if BANKS >= 2 ? $clog2(BANKS) : 1; + + alias module SRAM_WRAPPER = sram_wrapper; + + struct pzbcm_sram_read_data { + info: READ_INFO_TYPE , + data: logic, + } +} diff --git a/veryl/pzbcm_sram/pzbcm_sram_wrapper_default.veryl b/veryl/pzbcm_sram/pzbcm_sram_wrapper_default.veryl new file mode 100644 index 0000000..acce1ba --- /dev/null +++ b/veryl/pzbcm_sram/pzbcm_sram_wrapper_default.veryl @@ -0,0 +1,65 @@ +//======================================== +// +// Copyright (c) 2025 PEZY Computing, K.K. +// +//======================================== +pub module pzbcm_sram_wrapper_default for pzbcm_sram_wrapper_proto #( + param WORDS : u16 = 256 , + param DATA_WIDTH : u16 = 32 , + param POINTER_WIDTH : u16 = 8 , + param N_PORT : u16 = 1 , + param SRAM_CONFIG_TYPE: type = logic, +)( + i_clk : input clock , + i_enable : input logic , + i_pointer: input logic, + i_write : input logic , + i_data : input logic , + o_data : output logic , + i_config : input SRAM_CONFIG_TYPE , +) { + var mea : logic ; + var adra: logic; + var meb : logic ; + var adrb: logic; + + if N_PORT == 1 :g_single_port { + always_comb { + if i_write { + mea = i_enable[0]; + meb = '0; + } else { + mea = '0; + meb = i_enable[0]; + } + + adra = i_pointer[0]; + adrb = i_pointer[0]; + } + } else :g_dual_port { + always_comb { + mea = i_enable[0]; + adra = i_pointer[0]; + meb = i_enable[1]; + adrb = i_pointer[1]; + } + } + + inst u_ram: $std::ram #( + WORD_SIZE : WORDS , + ADDRESS_WIDTH: POINTER_WIDTH, + DATA_WIDTH : DATA_WIDTH , + BUFFER_OUT : true , + ) ( + i_clk : i_clk , + i_rst : '0 , + i_clr : '0 , + i_mea : mea , + i_wea : '1 , + i_adra: adra , + i_da : i_data, + i_meb : meb , + i_adrb: adrb , + o_qb : o_data, + ); +} diff --git a/veryl/pzbcm_sram/pzbcm_sram_wrapper_proto.veryl b/veryl/pzbcm_sram/pzbcm_sram_wrapper_proto.veryl new file mode 100644 index 0000000..17b170b --- /dev/null +++ b/veryl/pzbcm_sram/pzbcm_sram_wrapper_proto.veryl @@ -0,0 +1,20 @@ +//======================================== +// +// Copyright (c) 2025 PEZY Computing, K.K. +// +//======================================== +pub proto module pzbcm_sram_wrapper_proto #( + param WORDS : u16 , + param DATA_WIDTH : u16 , + param POINTER_WIDTH : u16 , + param N_PORT : u16 , + param SRAM_CONFIG_TYPE: type, +)( + i_clk : input clock , + i_enable : input logic , + i_pointer: input logic, + i_write : input logic , + i_data : input logic , + o_data : output logic , + i_config : input SRAM_CONFIG_TYPE , +); diff --git a/veryl/pzcorebus_common/pzcorebus_common_pkg.veryl b/veryl/pzcorebus_common/pzcorebus_common_pkg.veryl new file mode 100644 index 0000000..65c24f5 --- /dev/null +++ b/veryl/pzcorebus_common/pzcorebus_common_pkg.veryl @@ -0,0 +1,378 @@ +//======================================== +// +// Copyright (c) 2025 PEZY Computing, K.K. +// All Rights Reserved. +// +//======================================== +pub package pzcorebus_common_pkg { +//-------------------------------------------------------------- +// Typedef +//-------------------------------------------------------------- + enum pzcorebus_profile: bit<_> { + CSR , + MEMORY_L, + MEMORY_H, + } + + const PZCOREBUS_CSR : pzcorebus_profile = pzcorebus_profile::CSR; + const PZCOREBUS_MEMORY_L: pzcorebus_profile = pzcorebus_profile::MEMORY_L; + const PZCOREBUS_MEMORY_H: pzcorebus_profile = pzcorebus_profile::MEMORY_H; + + enum pzcorebus_mcmd_kind: logic<3> { + READ = 3'b001, + WRITE = 3'b100, + FULL_WRITE = 3'b101, + BROADCAST = 3'b110, + ATOMIC = 3'b111, + MESSAGE = 3'b010, + } + + const PZCOREBUS_READ_COMMAND : pzcorebus_mcmd_kind = pzcorebus_mcmd_kind::READ; + const PZCOREBUS_WRITE_COMMAND : pzcorebus_mcmd_kind = pzcorebus_mcmd_kind::WRITE; + const PZCOREBUS_FULL_WRITE_COMMAND: pzcorebus_mcmd_kind = pzcorebus_mcmd_kind::FULL_WRITE; + const PZCOREBUS_BROADCAST_COMMAND : pzcorebus_mcmd_kind = pzcorebus_mcmd_kind::BROADCAST; + const PZCOREBUS_ATOMIC_COMMAND : pzcorebus_mcmd_kind = pzcorebus_mcmd_kind::ATOMIC; + const PZCOREBUS_MESSAGE_COMMAND : pzcorebus_mcmd_kind = pzcorebus_mcmd_kind::MESSAGE; + + // [3] 1: non-posted request + // 0: posted request + // [2:0] see pzcorebus_mcmd_kind + enum pzcorebus_mcmd: logic<4> { + NULL = 4'b0_000, + READ = {1'b1, pzcorebus_mcmd_kind::READ }, + WRITE = {1'b0, pzcorebus_mcmd_kind::WRITE }, + WRITE_NP = {1'b1, pzcorebus_mcmd_kind::WRITE }, + FULL_WRITE = {1'b0, pzcorebus_mcmd_kind::FULL_WRITE}, + FULL_WRITE_NP = {1'b1, pzcorebus_mcmd_kind::FULL_WRITE}, + BROADCAST = {1'b0, pzcorebus_mcmd_kind::BROADCAST }, + ATOMIC = {1'b0, pzcorebus_mcmd_kind::ATOMIC }, + ATOMIC_NP = {1'b1, pzcorebus_mcmd_kind::ATOMIC }, + MESSAGE = {1'b0, pzcorebus_mcmd_kind::MESSAGE }, + MESSAGE_NP = {1'b1, pzcorebus_mcmd_kind::MESSAGE }, + } + + const PZCOREBUS_READ : pzcorebus_mcmd = pzcorebus_mcmd::READ; + const PZCOREBUS_WRITE : pzcorebus_mcmd = pzcorebus_mcmd::WRITE; + const PZCOREBUS_WRITE_NP : pzcorebus_mcmd = pzcorebus_mcmd::WRITE_NP; + const PZCOREBUS_FULL_WRITE : pzcorebus_mcmd = pzcorebus_mcmd::FULL_WRITE; + const PZCOREBUS_FULL_WRITE_NP: pzcorebus_mcmd = pzcorebus_mcmd::FULL_WRITE_NP; + const PZCOREBUS_BROADCAST : pzcorebus_mcmd = pzcorebus_mcmd::BROADCAST; + const PZCOREBUS_ATOMIC : pzcorebus_mcmd = pzcorebus_mcmd::ATOMIC; + const PZCOREBUS_ATOMIC_NP : pzcorebus_mcmd = pzcorebus_mcmd::ATOMIC_NP; + const PZCOREBUS_MESSAGE : pzcorebus_mcmd = pzcorebus_mcmd::MESSAGE; + const PZCOREBUS_MESSAGE_NP : pzcorebus_mcmd = pzcorebus_mcmd::MESSAGE_NP; + + const MCMD_KIND_WIDTH: u16 = $bits(pzcorebus_mcmd_kind); + const MCMD_KIND_BIT : u16 = 0; + const WITH_DATA_BIT : u16 = MCMD_KIND_BIT + MCMD_KIND_WIDTH - 1; + const NON_POSTED_BIT : u16 = WITH_DATA_BIT + 1; + + enum pzcorebus_sresp: logic { + RESPONSE = 1'b0, + RESPONSE_WITH_DATA = 1'b1, + } + + const PZCOREBUS_RESPONSE : pzcorebus_sresp = pzcorebus_sresp::RESPONSE; + const PZCOREBUS_RESPONSE_WITH_DATA: pzcorebus_sresp = pzcorebus_sresp::RESPONSE_WITH_DATA; + +//-------------------------------------------------------------- +// Configuration +//-------------------------------------------------------------- + #[ifdef(SYNTHESIS)] + const ENABLE_DEBUG: bbool = true; + #[else] + const ENABLE_DEBUG: bbool = false; + + #[ifndef(PZCOREBUS_DISABLE_SVA_CHECKER)] + const ENABLE_SVA_CHECKER: bbool = ENABLE_DEBUG; + #[else] + const ENABLE_SVA_CHECKER: bbool = false; + + struct pzcorebus_signal_info { + pos : u16, + width: u16, + } + + struct pzcorebus_mcmd_info { + mcmd : pzcorebus_signal_info, + mid : pzcorebus_signal_info, + maddr : pzcorebus_signal_info, + mlength : pzcorebus_signal_info, + mparam : pzcorebus_signal_info, + minfo : pzcorebus_signal_info, + mdata : pzcorebus_signal_info, + mdata_byteen : pzcorebus_signal_info, + mlength_unpacked_width: u16 , + mburst_length_width : u16 , + packed_width : u16 , + } + + struct pzcorebus_mdata_info { + mdata : pzcorebus_signal_info, + mdata_byteen: pzcorebus_signal_info, + mdata_last : pzcorebus_signal_info, + packed_width: u16 , + } + + struct pzcorebus_sresp_info { + sresp : pzcorebus_signal_info, + sid : pzcorebus_signal_info, + serror : pzcorebus_signal_info, + sdata : pzcorebus_signal_info, + sinfo : pzcorebus_signal_info, + sresp_uniten: pzcorebus_signal_info, + sresp_last : pzcorebus_signal_info, + packed_width: u16 , + } + + struct pzcorebus_config { + profile : pzcorebus_profile , + id_width : u16 , + address_width : u16 , + data_width : u16 , + unit_data_width : u16 , + max_data_width : u16 , + data_size : u16 , + max_data_size : u16 , + use_byte_enable : bbool , + byte_enable_width : u16 , + max_length : u16 , + max_burst_length : u16 , + atomic_command_width: u16 , + message_code_width : u16 , + request_info_width : u16 , + response_info_width : u16 , + response_boundary : u16 , + mcmd_info : pzcorebus_mcmd_info , + mdata_info : pzcorebus_mdata_info, + sresp_info : pzcorebus_sresp_info, + } + + function is_csr_profile(bus_config: input pzcorebus_config) -> bbool { + return bus_config.profile == pzcorebus_profile::CSR; + } + + function is_mem_l_profile(bus_config: input pzcorebus_config) -> bbool { + return bus_config.profile == pzcorebus_profile::MEMORY_L; + } + + function is_mem_h_profile(bus_config: input pzcorebus_config) -> bbool { + return bus_config.profile == pzcorebus_profile::MEMORY_H; + } + + function is_mem_profile(bus_config: input pzcorebus_config) -> bbool { + return is_mem_l_profile(bus_config) || is_mem_h_profile(bus_config); + } + + function get_data_byte_size(bus_config: input pzcorebus_config) -> u16 { + return bus_config.data_width / 8; + } + + function get_data_unit_size(bus_config: input pzcorebus_config) -> u16 { + if bus_config.profile == pzcorebus_profile::MEMORY_H { + return bus_config.data_width / bus_config.unit_data_width; + } else { + return bus_config.data_width; + } + } + + function get_signal_width( + width : input u16 , + typedef_width: input bbool, + ) -> u16 { + if typedef_width && width == 0 { + return 1; + } else { + return width; + } + } + + function calc_next_pos( + info: input pzcorebus_signal_info, + ) -> u16 { + return info.pos + info.width; + } + + function create_config( + profile : input pzcorebus_profile, + id_width : input u16 , + address_width : input u16 , + data_width : input u16 , + use_byte_enable : input bbool , + max_length : input u16 , + atomic_command_width: input u16 , + message_code_width : input u16 , + request_info_width : input u16 , + response_info_width : input u16 , + unit_data_width : input u16 , + max_data_width : input u16 , + response_boundary : input u16 , + ) -> pzcorebus_config { + var bus_config : pzcorebus_config ; + var mcmd_info : pzcorebus_mcmd_info ; + var mdata_info : pzcorebus_mdata_info; + var sresp_info : pzcorebus_sresp_info; + var is_csr : bbool ; + var is_memory_h: bbool ; + + is_csr = profile == pzcorebus_profile::CSR; + is_memory_h = profile == pzcorebus_profile::MEMORY_H; + + bus_config.profile = profile; + bus_config.id_width = id_width; + bus_config.address_width = address_width; + bus_config.data_width = data_width; + bus_config.unit_data_width = if is_memory_h ? unit_data_width : data_width; + bus_config.max_data_width = if is_memory_h ? max_data_width : data_width; + bus_config.data_size = bus_config.data_width / bus_config.unit_data_width; + bus_config.max_data_size = bus_config.max_data_width / bus_config.unit_data_width; + bus_config.use_byte_enable = use_byte_enable; + bus_config.byte_enable_width = if use_byte_enable ? data_width / 8 : 0; + bus_config.max_length = if is_csr ? 1 : max_length; + bus_config.max_burst_length = if is_csr ? 1 : max_length / bus_config.data_size; + bus_config.atomic_command_width = if is_csr ? 0 : atomic_command_width; + bus_config.message_code_width = if is_csr ? 0 : message_code_width; + bus_config.request_info_width = request_info_width; + bus_config.response_info_width = response_info_width; + bus_config.response_boundary = response_boundary; + + // mcmd info + mcmd_info.mcmd.pos = 0; + mcmd_info.mcmd.width = $bits(pzcorebus_mcmd); + mcmd_info.mid.pos = calc_next_pos(mcmd_info.mcmd); + mcmd_info.mid.width = bus_config.id_width; + mcmd_info.maddr.pos = calc_next_pos(mcmd_info.mid); + mcmd_info.maddr.width = bus_config.address_width; + mcmd_info.mlength.pos = calc_next_pos(mcmd_info.maddr); + if is_csr { + mcmd_info.mlength.width = 0; + } else if bus_config.max_length >= 2 { + mcmd_info.mlength.width = $clog2(bus_config.max_length); + } else { + mcmd_info.mlength.width = 1; + } + mcmd_info.mparam.pos = calc_next_pos(mcmd_info.mlength); + if bus_config.atomic_command_width >= bus_config.message_code_width { + mcmd_info.mparam.width = bus_config.atomic_command_width; + } else { + mcmd_info.mparam.width = bus_config.message_code_width; + } + mcmd_info.minfo.pos = calc_next_pos(mcmd_info.mparam); + mcmd_info.minfo.width = request_info_width; + if is_csr { + mcmd_info.mdata.pos = calc_next_pos(mcmd_info.minfo); + mcmd_info.mdata.width = data_width; + mcmd_info.mdata_byteen.pos = calc_next_pos(mcmd_info.mdata); + mcmd_info.mdata_byteen.width = bus_config.byte_enable_width; + mcmd_info.mlength_unpacked_width = 1; + mcmd_info.mburst_length_width = 1; + } else { + mcmd_info.mdata.pos = calc_next_pos(mcmd_info.minfo); + mcmd_info.mdata.width = 0; + mcmd_info.mdata_byteen.pos = calc_next_pos(mcmd_info.mdata); + mcmd_info.mdata_byteen.width = 0; + mcmd_info.mlength_unpacked_width = $clog2(bus_config.max_length + 1); + mcmd_info.mburst_length_width = $clog2(bus_config.max_burst_length + 1); + } + mcmd_info.packed_width = mcmd_info.mcmd.width + + mcmd_info.mid.width + + mcmd_info.maddr.width + + mcmd_info.mlength.width + + mcmd_info.mparam.width + + mcmd_info.minfo.width + + mcmd_info.mdata.width + + mcmd_info.mdata_byteen.width; + + // mdata info + if !is_csr { + mdata_info.mdata_last.pos = 0; + mdata_info.mdata_last.width = 1; + mdata_info.mdata.pos = calc_next_pos(mdata_info.mdata_last); + mdata_info.mdata.width = data_width; + mdata_info.mdata_byteen.pos = calc_next_pos(mdata_info.mdata); + mdata_info.mdata_byteen.width = bus_config.byte_enable_width; + mdata_info.packed_width = mdata_info.mdata_last.width + + mdata_info.mdata.width + + mdata_info.mdata_byteen.width; + } else { + mdata_info = 0 as pzcorebus_mdata_info; + } + + // sresp info + sresp_info.sresp.pos = 0; + sresp_info.sresp.width = $bits(pzcorebus_sresp); + sresp_info.sid.pos = calc_next_pos(sresp_info.sresp); + sresp_info.sid.width = id_width; + sresp_info.serror.pos = calc_next_pos(sresp_info.sid); + sresp_info.serror.width = 1; + sresp_info.sdata.pos = calc_next_pos(sresp_info.serror); + sresp_info.sdata.width = data_width; + sresp_info.sinfo.pos = calc_next_pos(sresp_info.sdata); + sresp_info.sinfo.width = response_info_width; + sresp_info.sresp_uniten.pos = calc_next_pos(sresp_info.sinfo); + if is_memory_h { + sresp_info.sresp_uniten.width = bus_config.max_data_width / bus_config.unit_data_width; + } else { + sresp_info.sresp_uniten.width = 0; + } + sresp_info.sresp_last.pos = calc_next_pos(sresp_info.sresp_uniten); + if is_csr { + sresp_info.sresp_last.width = 0; + } else if is_memory_h { + sresp_info.sresp_last.width = 2; + } else { + sresp_info.sresp_last.width = 1; + } + sresp_info.packed_width = sresp_info.sresp.width + + sresp_info.sid.width + + sresp_info.serror.width + + sresp_info.sdata.width + + sresp_info.sinfo.width + + sresp_info.sresp_uniten.width + + sresp_info.sresp_last.width; + + bus_config.mcmd_info = mcmd_info; + bus_config.mdata_info = mdata_info; + bus_config.sresp_info = sresp_info; + return bus_config; + } + + function get_sresp_size_width( + bus_config: input pzcorebus_config, + ) -> u16 { + if is_mem_h_profile(bus_config) { + return $clog2(bus_config.data_size + 1); + } else { + return 1; + } + } + + function get_sresp_offset_width( + bus_config : input pzcorebus_config, + typedef_width: input bbool , + ) -> u16 { + var width: u16; + + if is_mem_h_profile(bus_config) { + width = $clog2(bus_config.max_data_size); + } else { + width = 1; + } + + return get_signal_width(width, typedef_width); + } + + function get_sresp_offset_lsb( + bus_config: input pzcorebus_config, + ) -> u16 { + if is_mem_h_profile(bus_config) { + return $clog2(bus_config.unit_data_width / 8); + } else { + return 0; + } + } +} + +embed (inline) sv {{{ + `define PZCOREBUS_COMMON_PKG \{ pzcorebus_common_pkg \} +}}} diff --git a/veryl/pzcorebus_common/pzcorebus_id_assigner.veryl b/veryl/pzcorebus_common/pzcorebus_id_assigner.veryl new file mode 100644 index 0000000..b1afe9b --- /dev/null +++ b/veryl/pzcorebus_common/pzcorebus_id_assigner.veryl @@ -0,0 +1,39 @@ +//======================================== +// +// Copyright (c) 2026 PEZY Computing, K.K. +// +//======================================== +pub module pzcorebus_id_assigner:: #( + param LOCAL_ID_WIDTH: u32 = PKG::BUS_CONFIG.id_width - 1 , + param LOCAL_ID_LSB : u32 = 0 , + param BASE_ID_WIDTH : u32 = PKG::BUS_CONFIG.id_width - LOCAL_ID_WIDTH, + param BASE_ID_LSB : u32 = LOCAL_ID_WIDTH , + const BASE_ID_WIDTH_: u32 = if BASE_ID_WIDTH >: 0 ? BASE_ID_WIDTH : 1, +)( + i_base_id: input logic , + slave_if : modport pzcorebus_if::::slave , + master_if: modport pzcorebus_if::::master, +){ + import PKG::pzcorebus_id; + + const ID_MASK: pzcorebus_id = (1 << LOCAL_ID_WIDTH) - 1; + + function get_mid( + mid : input pzcorebus_id , + base_id: input logic, + ) -> pzcorebus_id { + return (base_id << BASE_ID_LSB) as pzcorebus_id | ((mid & ID_MASK) << LOCAL_ID_LSB) as pzcorebus_id; + } + + function get_sid( + sid: input pzcorebus_id, + ) -> pzcorebus_id { + return ((sid >> LOCAL_ID_LSB) & ID_MASK) as pzcorebus_id; + } + + always_comb { + slave_if <> master_if; + master_if.mid = get_mid(slave_if.mid, i_base_id); + slave_if.sid = get_sid(master_if.sid); + } +} diff --git a/veryl/pzcorebus_common/pzcorebus_if.veryl b/veryl/pzcorebus_common/pzcorebus_if.veryl new file mode 100644 index 0000000..395b377 --- /dev/null +++ b/veryl/pzcorebus_common/pzcorebus_if.veryl @@ -0,0 +1,563 @@ +//======================================== +// +// Copyright (c) 2025 PEZY Computing, K.K. +// +//======================================== +pub interface pzcorebus_if:: { + import PKG::*; + import pzcorebus_common_pkg::pzcorebus_mcmd_info; + import pzcorebus_common_pkg::pzcorebus_mdata_info; + import pzcorebus_common_pkg::pzcorebus_sresp_info; + import pzcorebus_common_pkg::pzcorebus_signal_info; + + const MCMD_INFO : pzcorebus_mcmd_info = BUS_CONFIG.mcmd_info ; + const MDATA_INFO: pzcorebus_mdata_info = BUS_CONFIG.mdata_info; + const SRESP_INFO: pzcorebus_sresp_info = BUS_CONFIG.sresp_info; + const IS_CSR : bbool = pzcorebus_common_pkg::is_csr_profile(BUS_CONFIG); + const IS_MEM : bbool = pzcorebus_common_pkg::is_mem_profile(BUS_CONFIG); + const IS_MEM_H : bbool = pzcorebus_common_pkg::is_mem_h_profile(BUS_CONFIG); + + var scmd_accept : logic ; + var mcmd_valid : logic ; + var mcmd : pzcorebus_mcmd ; + var mid : pzcorebus_mid ; + var maddr : pzcorebus_maddr ; + var mlength : pzcorebus_mlength ; + var mparam : pzcorebus_mparam ; + var minfo : pzcorebus_minfo ; + var sdata_accept: logic ; + var mdata_valid : logic ; + var mdata : pzcorebus_mdata ; + var mdata_byteen: pzcorebus_mdata_byteen; + var mdata_last : pzcorebus_mdata_last ; + var mresp_accept: logic ; + var sresp_valid : logic ; + var sresp : pzcorebus_sresp ; + var sid : pzcorebus_sid ; + var serror : pzcorebus_serror ; + var sdata : pzcorebus_sdata ; + var sinfo : pzcorebus_sinfo ; + var sresp_uniten: pzcorebus_sresp_uniten; + var sresp_last : pzcorebus_sresp_last ; + +//-------------------------------------------------------------- +// Internal functions +//-------------------------------------------------------------- + function pack_field::< + PACKER: type , + T : type , + INFO : pzcorebus_signal_info, + >( + packer: input PACKER, + value : input T , + ) -> PACKER { + const WIDTH: u16 = if INFO.width >: 0 ? INFO.width : 1; + + var packer_next: PACKER; + packer_next = packer; + + if INFO.width >: 0 { + packer_next[INFO.pos+:WIDTH] = value; + } + + return packer_next; + } + + function unpack_field::< + PACKER: type , + T : type , + INFO : pzcorebus_signal_info, + >(packer: input PACKER) -> T { + const WIDTH: u16 = if INFO.width >: 0 ? INFO.width : 1; + if INFO.width >: 0 { + return packer[INFO.pos+:WIDTH] as T; + } else { + return 'x as T; + } + } + +//-------------------------------------------------------------- +// API +//-------------------------------------------------------------- + alias package utils_pkg = pzcorebus_utils_pkg::; + + function get_mcmd() -> pzcorebus_bundled_mcmd { + var bundled_mcmd: pzcorebus_bundled_mcmd; + bundled_mcmd.mcmd = mcmd; + bundled_mcmd.mid = mid; + bundled_mcmd.maddr = maddr; + bundled_mcmd.mlength = mlength; + bundled_mcmd.mparam = mparam; + bundled_mcmd.minfo = minfo; + if IS_CSR { + bundled_mcmd.mdata = mdata; + bundled_mcmd.mdata_byteen = mdata_byteen; + } else { + bundled_mcmd.mdata = '0; + bundled_mcmd.mdata_byteen = '0; + } + + return bundled_mcmd; + } + + function put_mcmd(bundled_mcmd: input pzcorebus_bundled_mcmd) { + mcmd = bundled_mcmd.mcmd; + mid = bundled_mcmd.mid; + maddr = bundled_mcmd.maddr; + mlength = bundled_mcmd.mlength; + mparam = bundled_mcmd.mparam; + minfo = bundled_mcmd.minfo; + if IS_CSR { + mdata = bundled_mcmd.mdata; + mdata_byteen = bundled_mcmd.mdata_byteen; + } + } + + function get_mdata() -> pzcorebus_bundled_mdata { + var bundled_mdata: pzcorebus_bundled_mdata; + + if IS_MEM { + bundled_mdata.mdata = mdata; + bundled_mdata.mdata_byteen = mdata_byteen; + bundled_mdata.mdata_last = mdata_last; + } else { + bundled_mdata.mdata = '0; + bundled_mdata.mdata_byteen = '0; + bundled_mdata.mdata_last = '0; + } + + return bundled_mdata; + } + + function put_mdata(bundled_mdata: input pzcorebus_bundled_mdata) { + if IS_MEM { + mdata = bundled_mdata.mdata; + mdata_byteen = bundled_mdata.mdata_byteen; + mdata_last = bundled_mdata.mdata_last; + } + } + + function get_sresp() -> pzcorebus_bundled_sresp { + var bundled_sresp: pzcorebus_bundled_sresp; + + bundled_sresp.sresp = sresp; + bundled_sresp.sid = sid; + bundled_sresp.serror = serror; + bundled_sresp.sdata = sdata; + bundled_sresp.sinfo = sinfo; + bundled_sresp.sresp_uniten = sresp_uniten; + bundled_sresp.sresp_last = sresp_last; + + return bundled_sresp; + } + + function put_sresp(bundled_sresp: input pzcorebus_bundled_sresp) { + sresp = bundled_sresp.sresp; + sid = bundled_sresp.sid; + serror = bundled_sresp.serror; + sdata = bundled_sresp.sdata; + sinfo = bundled_sresp.sinfo; + sresp_uniten = bundled_sresp.sresp_uniten; + sresp_last = bundled_sresp.sresp_last; + } + + function get_packed_mcmd() -> pzcorebus_packed_mcmd { + var packer: pzcorebus_mcmd_packer; + + packer = pack_field::(packer, mcmd); + packer = pack_field::(packer, mid); + packer = pack_field::(packer, maddr); + packer = pack_field::(packer, mlength); + packer = pack_field::(packer, mparam); + packer = pack_field::(packer, minfo); + if IS_CSR { + packer = pack_field::(packer, mdata); + packer = pack_field::(packer, mdata_byteen); + } + + return packer as pzcorebus_packed_mcmd; + } + + function put_packed_mcmd(packed_mcmd: input pzcorebus_packed_mcmd) { + let packer: pzcorebus_mcmd_packer = packed_mcmd as pzcorebus_mcmd_packer; + + mcmd = unpack_field::(packer); + mid = unpack_field::(packer); + maddr = unpack_field::(packer); + mlength = unpack_field::(packer); + mparam = unpack_field::(packer); + minfo = unpack_field::(packer); + if IS_CSR { + mdata = unpack_field::(packer); + mdata_byteen = unpack_field::(packer); + } + } + + function get_packed_mdata() -> pzcorebus_packed_mdata { + var packer: pzcorebus_mdata_packer; + + if IS_MEM { + packer = pack_field::(packer, mdata); + packer = pack_field::(packer, mdata_byteen); + packer = pack_field::(packer, mdata_last); + } else { + packer = '0; + } + + return packer as pzcorebus_packed_mdata; + } + + function put_packed_mdata(packed_mdata: input pzcorebus_packed_mdata) { + if IS_MEM { + let packer: pzcorebus_mdata_packer = packed_mdata as pzcorebus_mdata_packer; + mdata = unpack_field::(packer); + mdata_byteen = unpack_field::(packer); + mdata_last = unpack_field::(packer); + } + } + + function get_packed_sresp() -> pzcorebus_packed_sresp { + var packer: pzcorebus_sresp_packer; + + packer = pack_field::(packer, sresp); + packer = pack_field::(packer, sid); + packer = pack_field::(packer, serror); + packer = pack_field::(packer, sdata); + packer = pack_field::(packer, sinfo); + packer = pack_field::(packer, sresp_uniten); + packer = pack_field::(packer, sresp_last); + + return packer as pzcorebus_packed_sresp; + } + + function put_packed_sresp(packed_sresp: input pzcorebus_packed_sresp) { + let packer: pzcorebus_sresp_packer = packed_sresp as pzcorebus_sresp_packer; + sresp = unpack_field::(packer); + sid = unpack_field::(packer); + serror = unpack_field::(packer); + sdata = unpack_field::(packer); + sinfo = unpack_field::(packer); + sresp_uniten = unpack_field::(packer); + sresp_last = unpack_field::(packer); + } + + function mcmd_kind() -> pzcorebus_mcmd_kind { + return utils_pkg::mcmd_kind(mcmd); + } + + function is_mcmd_posted() -> logic { + return utils_pkg::is_mcmd_posted(mcmd); + } + + function is_mcmd_non_posted() -> logic { + return utils_pkg::is_mcmd_non_posted(mcmd); + } + + function is_mcmd_no_data() -> logic { + return utils_pkg::is_mcmd_no_data(mcmd); + } + + function is_mcmd_with_data() -> logic { + return utils_pkg::is_mcmd_with_data(mcmd); + } + + function is_mcmd_atomic() -> logic { + return utils_pkg::is_mcmd_atomic(mcmd); + } + + function is_mcmd_message() -> logic { + return utils_pkg::is_mcmd_message(mcmd); + } + + function is_mcmd_with_response_data() -> logic { + return utils_pkg::is_mcmd_with_response_data(mcmd); + } + + function mcmd_ack() -> logic { + return scmd_accept && mcmd_valid; + } + + function mcmd_posted_ack() -> logic { + return mcmd_ack() && is_mcmd_posted(); + } + + function mcmd_non_posted_ack() -> logic { + return mcmd_ack() && is_mcmd_non_posted(); + } + + function mcmd_no_data_ack() -> logic { + return mcmd_ack() && is_mcmd_no_data(); + } + + function mcmd_with_data_ack() -> logic { + return mcmd_ack() && is_mcmd_with_data(); + } + + function mcmd_posted_valid() -> logic { + return mcmd_valid && is_mcmd_posted(); + } + + function mcmd_non_posted_valid() -> logic { + return mcmd_valid && is_mcmd_non_posted(); + } + + function mcmd_no_data_valid() -> logic { + return mcmd_valid && is_mcmd_no_data(); + } + + function mcmd_with_data_valid() -> logic { + return mcmd_valid && is_mcmd_with_data(); + } + + function mdata_ack() -> logic { + if IS_MEM { + return sdata_accept && mdata_valid; + } else { + return '0; + } + } + + function mdata_last_ack() -> logic { + return mdata_ack() && mdata_last; + } + + function is_sresp_no_data() -> logic { + return utils_pkg::is_sresp_no_data(sresp); + } + + function is_sresp_with_data() -> logic { + return utils_pkg::is_sresp_with_data(sresp); + } + + function sresp_ack() -> logic { + return mresp_accept && sresp_valid; + } + + function sresp_no_data_ack() -> logic { + return sresp_ack() && is_sresp_no_data(); + } + + function sresp_with_data_ack() -> logic { + return sresp_ack() && is_sresp_with_data(); + } + + function sresp_last_ack() -> logic { + if IS_MEM { + return sresp_ack() && sresp_last[0]; + } else { + return sresp_ack(); + } + } + + function sresp_sublast_ack() -> logic { + const FLAG_POS: u16 = $bits(pzcorebus_sresp_last) - 1; + if IS_MEM { + return sresp_ack() && sresp_last[FLAG_POS]; + } else { + return sresp_ack(); + } + } + + function get_mlength_unpacked() -> pzcorebus_mlength_unpacked { + return utils_pkg::get_mlength_unpacked(mcmd, mlength); + } + + function get_mlength_aligned() -> pzcorebus_mlength_unpacked { + return utils_pkg::get_mlength_aligned(mcmd, maddr, mlength); + } + + function get_mburst_length() -> pzcorebus_mburst_length { + return utils_pkg::get_mburst_length(mcmd, maddr, mlength); + } + + function get_sresp_length() -> pzcorebus_mlength_unpacked { + case mcmd_kind() { + pzcorebus_mcmd_kind::MESSAGE: return BUS_CONFIG.data_size as pzcorebus_mlength_unpacked; + default : return get_mlength_unpacked(); + } + } + + function get_sresp_offset() -> pzcorebus_sresp_offset { + const OFFSET_LSB : u16 = pzcorebus_common_pkg::get_sresp_offset_lsb(BUS_CONFIG); + const OFFSET_WIDTH: u16 = $bits(pzcorebus_sresp_offset); + + if IS_MEM_H && (mcmd_kind() == pzcorebus_mcmd_kind::READ) { + return maddr[OFFSET_LSB+:OFFSET_WIDTH]; + } else { + return 0 as pzcorebus_sresp_offset; + } + } + +//-------------------------------------------------------------- +// MOdport +//-------------------------------------------------------------- + modport master_mcmd { + scmd_accept : input , + mcmd_valid : output, + mcmd : output, + mid : output, + maddr : output, + mlength : output, + mparam : output, + minfo : output, + put_mcmd : import, + put_packed_mcmd : import, + mcmd_kind : import, + is_mcmd_posted : import, + is_mcmd_non_posted : import, + is_mcmd_no_data : import, + is_mcmd_with_data : import, + is_mcmd_atomic : import, + is_mcmd_message : import, + is_mcmd_with_response_data: import, + mcmd_ack : import, + mcmd_posted_ack : import, + mcmd_non_posted_ack : import, + mcmd_no_data_ack : import, + mcmd_with_data_ack : import, + mcmd_posted_valid : import, + mcmd_non_posted_valid : import, + mcmd_no_data_valid : import, + mcmd_with_data_valid : import, + get_mlength_unpacked : import, + get_mlength_aligned : import, + get_mburst_length : import, + } + + modport master_mdata { + sdata_accept : input , + mdata_valid : output, + mdata : output, + mdata_byteen : output, + mdata_last : output, + put_mdata : import, + put_packed_mdata : import, + mdata_ack : import, + mdata_last_ack : import, + } + + modport master_mreq { + ..same(master_mcmd, master_mdata) + } + + modport master_sresp { + mresp_accept : output, + sresp_valid : input , + sresp : input , + sid : input , + serror : input , + sdata : input , + sinfo : input , + sresp_uniten : input , + sresp_last : input , + get_sresp : import, + get_packed_sresp : import, + is_sresp_no_data : import, + is_sresp_with_data : import, + sresp_ack : import, + sresp_no_data_ack : import, + sresp_with_data_ack: import, + sresp_last_ack : import, + sresp_sublast_ack : import, + } + + modport master { + ..same(master_mreq, master_sresp) + } + + modport slave_mcmd { + get_mcmd : import, + get_packed_mcmd : import, + mcmd_kind : import, + is_mcmd_posted : import, + is_mcmd_non_posted : import, + is_mcmd_no_data : import, + is_mcmd_with_data : import, + is_mcmd_atomic : import, + is_mcmd_message : import, + is_mcmd_with_response_data: import, + mcmd_ack : import, + mcmd_posted_ack : import, + mcmd_non_posted_ack : import, + mcmd_no_data_ack : import, + mcmd_with_data_ack : import, + mcmd_posted_valid : import, + mcmd_non_posted_valid : import, + mcmd_no_data_valid : import, + mcmd_with_data_valid : import, + get_mlength_unpacked : import, + get_mlength_aligned : import, + get_mburst_length : import, + ..converse(master_mcmd) + } + + modport slave_mdata { + get_mdata : import, + get_packed_mdata : import, + mdata_ack : import, + mdata_last_ack : import, + ..converse(master_mdata) + } + + modport slave_mreq { + ..same(slave_mcmd, slave_mdata) + } + + modport slave_sresp { + put_sresp : import, + put_packed_sresp : import, + is_sresp_no_data : import, + is_sresp_with_data : import, + sresp_ack : import, + sresp_no_data_ack : import, + sresp_with_data_ack: import, + sresp_last_ack : import, + sresp_sublast_ack : import, + ..converse(master_sresp) + } + + modport slave { + ..same(slave_mreq, slave_sresp) + } + + modport monitor { + get_mcmd : import, + get_mdata : import, + get_sresp : import, + get_packed_mcmd : import, + get_packed_mdata : import, + get_packed_sresp : import, + mcmd_kind : import, + is_mcmd_posted : import, + is_mcmd_non_posted : import, + is_mcmd_no_data : import, + is_mcmd_with_data : import, + is_mcmd_atomic : import, + is_mcmd_message : import, + is_mcmd_with_response_data: import, + mcmd_ack : import, + mcmd_posted_ack : import, + mcmd_non_posted_ack : import, + mcmd_no_data_ack : import, + mcmd_with_data_ack : import, + mcmd_posted_valid : import, + mcmd_non_posted_valid : import, + mcmd_no_data_valid : import, + mcmd_with_data_valid : import, + mdata_ack : import, + mdata_last_ack : import, + is_sresp_no_data : import, + is_sresp_with_data : import, + sresp_ack : import, + sresp_no_data_ack : import, + sresp_with_data_ack : import, + sresp_last_ack : import, + sresp_sublast_ack : import, + get_mlength_unpacked : import, + get_mlength_aligned : import, + get_mburst_length : import, + get_sresp_length : import, + get_sresp_offset : import, + ..input + } +} diff --git a/veryl/pzcorebus_common/pzcorebus_pkg.veryl b/veryl/pzcorebus_common/pzcorebus_pkg.veryl new file mode 100644 index 0000000..86fbc7b --- /dev/null +++ b/veryl/pzcorebus_common/pzcorebus_pkg.veryl @@ -0,0 +1,173 @@ +//======================================== +// +// Copyright (c) 2025 PEZY Computing, K.K. +// All Rights Reserved. +// +//======================================== +pub proto package pzcorebus_proto_pkg { + type pzcorebus_config = pzcorebus_common_pkg::pzcorebus_config ; + type pzcorebus_profile = pzcorebus_common_pkg::pzcorebus_profile; + + const BUS_CONFIG: pzcorebus_config; + + type pzcorebus_id ; + type pzcorebus_data; + + type pzcorebus_mcmd_kind = pzcorebus_common_pkg::pzcorebus_mcmd_kind; + type pzcorebus_mcmd = pzcorebus_common_pkg::pzcorebus_mcmd ; + type pzcorebus_mid ; + type pzcorebus_maddr ; + type pzcorebus_mlength ; + type pzcorebus_mlength_unpacked; + type pzcorebus_mburst_length ; + type pzcorebus_mparam ; + type pzcorebus_minfo ; + type pzcorebus_mdata ; + type pzcorebus_mdata_byteen ; + type pzcorebus_mdata_last ; + type pzcorebus_sresp = pzcorebus_common_pkg::pzcorebus_sresp; + type pzcorebus_sid ; + type pzcorebus_serror ; + type pzcorebus_sdata ; + type pzcorebus_sinfo ; + type pzcorebus_sresp_uniten ; + type pzcorebus_sresp_last ; + type pzcorebus_sresp_size ; + type pzcorebus_sresp_offset ; + + struct pzcorebus_bundled_mcmd { + mdata_byteen: pzcorebus_mdata_byteen, + mdata : pzcorebus_mdata , + minfo : pzcorebus_minfo , + mparam : pzcorebus_mparam , + mlength : pzcorebus_mlength , + maddr : pzcorebus_maddr , + mid : pzcorebus_mid , + mcmd : pzcorebus_mcmd , + } + + struct pzcorebus_bundled_mdata { + mdata_last : pzcorebus_mdata_last , + mdata_byteen: pzcorebus_mdata_byteen, + mdata : pzcorebus_mdata , + } + + struct pzcorebus_bundled_sresp { + sresp_last : pzcorebus_sresp_last , + sresp_uniten: pzcorebus_sresp_uniten, + sinfo : pzcorebus_sinfo , + sdata : pzcorebus_sdata , + serror : pzcorebus_serror , + sid : pzcorebus_id , + sresp : pzcorebus_sresp , + } + + type pzcorebus_packed_mcmd ; + type pzcorebus_packed_mdata; + type pzcorebus_packed_sresp; + + type pzcorebus_mcmd_packer ; + type pzcorebus_mdata_packer; + type pzcorebus_sresp_packer; +} + +pub package pzcorebus_pkg::< + profile : pzcorebus_common_pkg::pzcorebus_profile, + id_width : u16 , + address_width : u16 , + data_width : u16 , + use_byte_enable : bbool , + max_length : u16 , + atomic_command_width: u16 , + message_code_width : u16 , + request_info_width : u16 , + response_info_width : u16 , + unit_data_width : u16 , + max_data_width : u16 , + response_boundary : u16 , +> for pzcorebus_proto_pkg { + import pzcorebus_common_pkg::create_config; + import pzcorebus_common_pkg::get_signal_width; + import pzcorebus_common_pkg::get_sresp_size_width; + import pzcorebus_common_pkg::get_sresp_offset_width; + + type pzcorebus_config = pzcorebus_common_pkg::pzcorebus_config ; + type pzcorebus_profile = pzcorebus_common_pkg::pzcorebus_profile; + + const BUS_CONFIG: pzcorebus_config = + create_config( + profile : profile , + id_width : id_width , + address_width : address_width , + data_width : data_width , + use_byte_enable : use_byte_enable , + max_length : max_length , + atomic_command_width: atomic_command_width, + message_code_width : message_code_width , + request_info_width : request_info_width , + response_info_width : response_info_width , + unit_data_width : unit_data_width , + max_data_width : max_data_width , + response_boundary : response_boundary , + ); + + type pzcorebus_id = logic; + type pzcorebus_data = logic; + + type pzcorebus_mcmd_kind = pzcorebus_common_pkg::pzcorebus_mcmd_kind; + type pzcorebus_mcmd = pzcorebus_common_pkg::pzcorebus_mcmd; + type pzcorebus_mid = pzcorebus_id; + type pzcorebus_maddr = logic; + type pzcorebus_mlength = logic; + type pzcorebus_mlength_unpacked = logic; + type pzcorebus_mburst_length = logic; + type pzcorebus_mparam = logic; + type pzcorebus_minfo = logic; + type pzcorebus_mdata = pzcorebus_data; + type pzcorebus_mdata_byteen = logic; + type pzcorebus_mdata_last = logic; + type pzcorebus_sresp = pzcorebus_common_pkg::pzcorebus_sresp; + type pzcorebus_sid = pzcorebus_id; + type pzcorebus_serror = logic; + type pzcorebus_sdata = pzcorebus_data; + type pzcorebus_sinfo = logic; + type pzcorebus_sresp_uniten = logic; + type pzcorebus_sresp_last = logic; + type pzcorebus_sresp_size = logic; + type pzcorebus_sresp_offset = logic; + + struct pzcorebus_bundled_mcmd { + mdata_byteen: pzcorebus_mdata_byteen, + mdata : pzcorebus_mdata , + minfo : pzcorebus_minfo , + mparam : pzcorebus_mparam , + mlength : pzcorebus_mlength , + maddr : pzcorebus_maddr , + mid : pzcorebus_mid , + mcmd : pzcorebus_mcmd , + } + + struct pzcorebus_bundled_mdata { + mdata_last : pzcorebus_mdata_last , + mdata_byteen: pzcorebus_mdata_byteen, + mdata : pzcorebus_mdata , + } + + struct pzcorebus_bundled_sresp { + sresp_last : pzcorebus_sresp_last , + sresp_uniten: pzcorebus_sresp_uniten, + sinfo : pzcorebus_sinfo , + sdata : pzcorebus_sdata , + serror : pzcorebus_serror , + sid : pzcorebus_id , + sresp : pzcorebus_sresp , + } + + type pzcorebus_packed_mcmd = logic; + type pzcorebus_packed_mdata = logic; + type pzcorebus_packed_sresp = logic; + + type pzcorebus_mcmd_packer = logic; + type pzcorebus_mdata_packer = logic; + type pzcorebus_sresp_packer = logic; +} diff --git a/veryl/pzcorebus_common/pzcorebus_utils_pkg.veryl b/veryl/pzcorebus_common/pzcorebus_utils_pkg.veryl new file mode 100644 index 0000000..9431261 --- /dev/null +++ b/veryl/pzcorebus_common/pzcorebus_utils_pkg.veryl @@ -0,0 +1,114 @@ +//======================================== +// +// Copyright (c) 2026 PEZY Computing, K.K. +// +//======================================== +pub package pzcorebus_utils_pkg:: { + const IS_CSR : bbool = pzcorebus_common_pkg::is_csr_profile(PKG::BUS_CONFIG); + const IS_MEM : bbool = pzcorebus_common_pkg::is_mem_profile(PKG::BUS_CONFIG); + const IS_MEM_H: bbool = pzcorebus_common_pkg::is_mem_h_profile(PKG::BUS_CONFIG); + + function mcmd_kind(mcmd: input PKG::pzcorebus_mcmd) -> PKG::pzcorebus_mcmd_kind { + return mcmd as PKG::pzcorebus_mcmd_kind; + } + + function is_mcmd_posted(mcmd: input PKG::pzcorebus_mcmd) -> logic { + return !mcmd[pzcorebus_common_pkg::NON_POSTED_BIT]; + } + + function is_mcmd_non_posted(mcmd: input PKG::pzcorebus_mcmd) -> logic { + return mcmd[pzcorebus_common_pkg::NON_POSTED_BIT]; + } + + function is_mcmd_no_data(mcmd: input PKG::pzcorebus_mcmd) -> logic { + return !mcmd[pzcorebus_common_pkg::WITH_DATA_BIT]; + } + + function is_mcmd_with_data(mcmd: input PKG::pzcorebus_mcmd) -> logic { + return mcmd[pzcorebus_common_pkg::WITH_DATA_BIT]; + } + + function is_mcmd_atomic(mcmd: input PKG::pzcorebus_mcmd) -> logic { + return IS_MEM && (mcmd_kind(mcmd) == PKG::pzcorebus_mcmd_kind::ATOMIC); + } + + function is_mcmd_message(mcmd: input PKG::pzcorebus_mcmd) -> logic { + return IS_MEM && (mcmd_kind(mcmd) == PKG::pzcorebus_mcmd_kind::MESSAGE); + } + + function is_mcmd_with_response_data(mcmd: input PKG::pzcorebus_mcmd) -> logic { + if IS_MEM { + return inside mcmd { PKG::pzcorebus_mcmd::READ, PKG::pzcorebus_mcmd::ATOMIC_NP }; + } else { + return mcmd_kind(mcmd) == PKG::pzcorebus_mcmd_kind::READ; + } + } + + function is_sresp_no_data(sresp: input PKG::pzcorebus_sresp) -> logic { + return sresp == PKG::pzcorebus_sresp::RESPONSE; + } + + function is_sresp_with_data(sresp: input PKG::pzcorebus_sresp) -> logic { + return sresp == PKG::pzcorebus_sresp::RESPONSE_WITH_DATA; + } + + function unpack_mlength( + mlength: input PKG::pzcorebus_mlength, + ) -> PKG::pzcorebus_mlength_unpacked { + if mlength == '0 { + return PKG::BUS_CONFIG.max_length as PKG::pzcorebus_mlength_unpacked; + } else { + return mlength as PKG::pzcorebus_mlength_unpacked; + } + } + + function get_mlength_unpacked( + mcmd : input PKG::pzcorebus_mcmd , + mlength: input PKG::pzcorebus_mlength, + ) -> PKG::pzcorebus_mlength_unpacked { + if IS_CSR { + return 1 as PKG::pzcorebus_mlength_unpacked; + } else if is_mcmd_message(mcmd) { + return 0 as PKG::pzcorebus_mlength_unpacked; + } else { + return unpack_mlength(mlength); + } + } + + function get_mlength_aligned( + mcmd : input PKG::pzcorebus_mcmd , + maddr : input PKG::pzcorebus_maddr , + mlength: input PKG::pzcorebus_mlength, + ) -> PKG::pzcorebus_mlength_unpacked { + const OFFSET_LSB : u16 = $clog2(PKG::BUS_CONFIG.unit_data_width) - 3; + const OFFSET_WIDTH: u16 = $std::utils::clog2_clipped(PKG::BUS_CONFIG.data_size, 1); + + var offset: logic; + if PKG::BUS_CONFIG.data_size == 1 || is_mcmd_message(mcmd) || is_mcmd_atomic(mcmd) { + offset = 0 as OFFSET_WIDTH; + } else { + offset = maddr[OFFSET_LSB+:OFFSET_WIDTH]; + } + + return get_mlength_unpacked(mcmd, mlength) + (offset as PKG::pzcorebus_mlength_unpacked); + } + + function get_mburst_length( + mcmd : input PKG::pzcorebus_mcmd , + maddr : input PKG::pzcorebus_maddr , + mlength: input PKG::pzcorebus_mlength, + ) -> PKG::pzcorebus_mburst_length { + if IS_CSR { + return 1 as PKG::pzcorebus_mburst_length; + } else { + var mlength_unpaced: PKG::pzcorebus_mlength_unpacked; + + mlength_unpaced = get_mlength_unpacked(mcmd, mlength); + if PKG::BUS_CONFIG.data_size >: 1 { + mlength_unpaced += ((PKG::BUS_CONFIG.data_size - 1) as PKG::pzcorebus_mlength_unpacked); + } + + return (mlength_unpaced / PKG::BUS_CONFIG.data_size) as PKG::pzcorebus_mburst_length; + } + } +} diff --git a/veryl/pzcorebus_csrbus_adapter/pzcorebus_csrbus_adapter.veryl b/veryl/pzcorebus_csrbus_adapter/pzcorebus_csrbus_adapter.veryl new file mode 100644 index 0000000..0c4d23a --- /dev/null +++ b/veryl/pzcorebus_csrbus_adapter/pzcorebus_csrbus_adapter.veryl @@ -0,0 +1,523 @@ +//======================================== +// +// Copyright (c) 2026 PEZY Computing, K.K. +// +//======================================== +pub module pzcorebus_csrbus_adapter::< + MEMBUS_PKG: pzcorebus_proto_pkg, + CSRBUS_PKG: pzcorebus_proto_pkg, +> #( + param MAX_NP_REUQESTS : u32 = 2 , + param SRESP_INFO_DEPTH : u32 = MAX_NP_REUQESTS , + param CSRBUS_ADDRESS_WIDTH: u32 = CSRBUS_PKG::BUS_CONFIG.address_width, + param SLAVE_SLICER_MCMD : bbool = true , + param SLAVE_SLICER_MDATA : bbool = true , + param SLAVE_SLICER_SRESP : bbool = true , + param MASTER_SLICER_MCMD : bbool = true , + param MASTER_SLICER_SRESP : bbool = true , +)( + i_clk : input clock , + i_rst : input reset , + i_base_id : input CSRBUS_PKG::pzcorebus_id , + i_force_np_write : input logic , + i_wait_for_all_sresp: input logic , + membus_slave_if : modport pzcorebus_if::::slave , + csrbus_master_if : modport pzcorebus_if::::master, +) { + const UNITEN_COUNT_WIDTH: u32 = $clog2(MEMBUS_PKG::BUS_CONFIG.max_data_size); + const UNIT_OFFSET_LSB : u32 = $clog2(MEMBUS_PKG::BUS_CONFIG.unit_data_width / 8); + const UNIT_OFFSET_WIDTH : u32 = $clog2(MEMBUS_PKG::BUS_CONFIG.data_size); + const UNIT_ADDRESS_WIDTH: u32 = CSRBUS_ADDRESS_WIDTH - UNIT_OFFSET_LSB; + const DATA_COUNT_WIDTH : u32 = UNIT_OFFSET_WIDTH; + + gen MINFO_WIDTH: u32 = MEMBUS_PKG::BUS_CONFIG.request_info_width + 2; + + alias package MEMBUS_INTERNAL_PKG = pzcorebus_pkg::< + MEMBUS_PKG::BUS_CONFIG.profile , //profile + MEMBUS_PKG::BUS_CONFIG.id_width , //id_width + MEMBUS_PKG::BUS_CONFIG.address_width , //address_width + MEMBUS_PKG::BUS_CONFIG.data_width , //data_width + MEMBUS_PKG::BUS_CONFIG.use_byte_enable , //use_byte_enable + MEMBUS_PKG::BUS_CONFIG.max_length , //max_length + 0 , //atomic_command_width + 0 , //message_code_width + MINFO_WIDTH , //request_info_width + MEMBUS_PKG::BUS_CONFIG.response_info_width, //response_info_width + MEMBUS_PKG::BUS_CONFIG.unit_data_width , //unit_data_width + MEMBUS_PKG::BUS_CONFIG.max_data_width , //max_data_width + MEMBUS_PKG::BUS_CONFIG.response_boundary , //response_boundary + >; + + struct pzcorebus_sideband_info { + minfo : MEMBUS_PKG::pzcorebus_minfo, + force_np_write : logic, + wait_for_all_sresp: logic, + } + + struct pzcorebus_sresp_info { + sresp : MEMBUS_PKG::pzcorebus_sresp, + sid : MEMBUS_PKG::pzcorebus_id , + uniten_offset : logic , + ignore_response: logic , + } + + inst membus_if: pzcorebus_if::; + inst slicer_if: pzcorebus_if::; + inst csrbus_if: pzcorebus_if:: ; + + var sideband_info : pzcorebus_sideband_info ; + var info_fifo_empty : logic ; + var info_fifo_full : logic ; + var info_fifo_push : logic ; + var info_fifo_pop : logic ; + var sresp_info : pzcorebus_sresp_info[2] ; + var sresp_count_empty: logic ; + var sresp_count_push : logic ; + var sresp_count : MEMBUS_PKG::pzcorebus_mlength_unpacked[2]; + +//-------------------------------------------------------------- +// Slicer +//-------------------------------------------------------------- + always_comb { + membus_if.master <> membus_slave_if; + membus_if.minfo = get_sideband_info(membus_slave_if.minfo, i_force_np_write, i_wait_for_all_sresp); + } + + inst u_slicer: pzcorebus_slicer:: #( + MCMD_VALID : SLAVE_SLICER_MCMD , + MDATA_VALID: SLAVE_SLICER_MDATA, + SRESP_VALID: SLAVE_SLICER_SRESP, + )( + i_clk : i_clk , + i_rst : i_rst , + slave_if : membus_if, + master_if: slicer_if, + ); + + function get_sideband_info( + minfo : input MEMBUS_PKG::pzcorebus_minfo, + force_np_write : input logic , + wait_for_all_sresp: input logic , + ) -> MEMBUS_INTERNAL_PKG::pzcorebus_minfo { + var info: pzcorebus_sideband_info ; + + info.minfo = minfo; + info.force_np_write = force_np_write; + info.wait_for_all_sresp = wait_for_all_sresp; + + return info as MEMBUS_INTERNAL_PKG::pzcorebus_minfo; + } + +//-------------------------------------------------------------- +// Request paht +//-------------------------------------------------------------- + :g_mreq_path { + var busy : logic ; + var write_data_inactive: logic ; + var read_valid : logic ; + var write_valid : logic ; + var length_count : MEMBUS_INTERNAL_PKG::pzcorebus_mlength_unpacked; + var length_count_last : logic ; + var data_count : logic ; + var data_count_last : logic ; + var mcmd : MEMBUS_INTERNAL_PKG::pzcorebus_mcmd[2] ; + var maddr : MEMBUS_INTERNAL_PKG::pzcorebus_maddr ; + var mreq_count : MEMBUS_INTERNAL_PKG::pzcorebus_mlength_unpacked; + var mreq_count_next : MEMBUS_INTERNAL_PKG::pzcorebus_mlength_unpacked; + var update : logic<2> ; + + always_comb { + length_count_last = length_count == (1 as MEMBUS_INTERNAL_PKG::pzcorebus_mlength_unpacked); + data_count_last = data_count == ((MEMBUS_PKG::BUS_CONFIG.data_size - 1) as DATA_COUNT_WIDTH); + mreq_count_next = mreq_count + (1 as MEMBUS_INTERNAL_PKG::pzcorebus_mlength_unpacked); + update[0] = csrbus_if.mcmd_ack(); + update[1] = write_valid && write_data_inactive; + } + + always_ff { + if_reset { + busy = false; + } else if (update != '0) && length_count_last { + busy = false; + } else if slicer_if.mcmd_ack() { + busy = true; + } + } + + always_comb { + mcmd[0] = get_mcmd(slicer_if.mcmd, slicer_if.minfo as pzcorebus_sideband_info); + } + + always_ff { + if_reset { + mcmd[1] = pzcorebus_common_pkg::pzcorebus_mcmd::NULL; + sideband_info = '0; + } else if slicer_if.mcmd_ack() { + mcmd[1] = mcmd[0]; + sideband_info = slicer_if.minfo as pzcorebus_sideband_info; + } + } + + always_ff { + if_reset { + length_count = 0 as MEMBUS_INTERNAL_PKG::pzcorebus_mlength_unpacked; + data_count = 0 as DATA_COUNT_WIDTH; + maddr = 0 as CSRBUS_PKG::pzcorebus_maddr; + } else if slicer_if.mcmd_ack() { + length_count = slicer_if.get_mlength_unpacked(); + data_count = slicer_if.maddr[UNIT_OFFSET_LSB+:UNIT_OFFSET_WIDTH]; + maddr = get_maddr_initial(slicer_if.maddr); + } else if update != '0 { + length_count -= (1 as MEMBUS_INTERNAL_PKG::pzcorebus_mlength_unpacked); + data_count += (1 as DATA_COUNT_WIDTH); + maddr = get_maddr_next(maddr); + } + } + + always_ff { + if_reset { + mreq_count = 0 as MEMBUS_INTERNAL_PKG::pzcorebus_mlength_unpacked; + } else if (update != '0) && length_count_last { + mreq_count = 0 as MEMBUS_INTERNAL_PKG::pzcorebus_mlength_unpacked; + } else if update[0] { + mreq_count = mreq_count_next; + } + } + + always_comb { + slicer_if.scmd_accept = + (!busy) && ((!mcmd[0][pzcorebus_common_pkg::NON_POSTED_BIT]) || (!info_fifo_full)); + + write_data_inactive = is_write_data_inactive(slicer_if.mdata_byteen, data_count); + read_valid = busy && (mcmd[1] == pzcorebus_common_pkg::pzcorebus_mcmd::READ); + write_valid = busy && mcmd[1][pzcorebus_common_pkg::WITH_DATA_BIT] && slicer_if.mdata_valid; + if read_valid { + slicer_if.sdata_accept = false; + csrbus_if.mcmd_valid = true; + } else if write_valid { + slicer_if.sdata_accept = (csrbus_if.scmd_accept || write_data_inactive) && (data_count_last || length_count_last); + csrbus_if.mcmd_valid = !write_data_inactive; + } else { + slicer_if.sdata_accept = false; + csrbus_if.mcmd_valid = false; + } + + csrbus_if.mcmd = mcmd[1]; + csrbus_if.mid = 0 as CSRBUS_PKG::pzcorebus_id; + csrbus_if.maddr = maddr; + csrbus_if.minfo = sideband_info.minfo; + csrbus_if.mdata = get_mdata(slicer_if.mdata, data_count); + csrbus_if.mdata_byteen = get_mdata_byteen(slicer_if.mdata_byteen, data_count); + } + + always_comb { + csrbus_if.mlength = '0; + csrbus_if.mparam = '0; + csrbus_if.mdata_valid = false; + csrbus_if.mdata_last = false; + } + + always_comb { + info_fifo_push = slicer_if.mcmd_ack() && mcmd[0][pzcorebus_common_pkg::NON_POSTED_BIT]; + sresp_info[0] = get_sresp_info(slicer_if.get_mcmd(), sideband_info); + } + + always_comb { + sresp_count_push = (update != '0) && length_count_last && csrbus_if.is_mcmd_non_posted(); + if update[0] { + sresp_count[0] = mreq_count_next; + } else { + sresp_count[0] = mreq_count; + } + } + } + + function get_mcmd( + mcmd : input pzcorebus_common_pkg::pzcorebus_mcmd, + sideband_info: input pzcorebus_sideband_info , + ) -> pzcorebus_common_pkg::pzcorebus_mcmd { + if sideband_info.force_np_write && (mcmd == pzcorebus_common_pkg::pzcorebus_mcmd::WRITE) { + return pzcorebus_common_pkg::pzcorebus_mcmd::WRITE_NP; + } else if sideband_info.force_np_write && (mcmd == pzcorebus_common_pkg::pzcorebus_mcmd::FULL_WRITE) { + return pzcorebus_common_pkg::pzcorebus_mcmd::FULL_WRITE_NP; + } else { + return mcmd; + } + } + + function get_maddr_initial( + maddr: input MEMBUS_INTERNAL_PKG::pzcorebus_maddr, + ) -> CSRBUS_PKG::pzcorebus_maddr { + var maddr_initial: logic; + maddr_initial = {maddr[UNIT_OFFSET_LSB+:UNIT_ADDRESS_WIDTH], (0 as UNIT_OFFSET_LSB)}; + return maddr_initial as CSRBUS_PKG::pzcorebus_maddr; + } + + function get_maddr_next( + maddr: input CSRBUS_PKG::pzcorebus_maddr, + ) -> CSRBUS_PKG::pzcorebus_maddr { + var maddr_next: logic; + maddr_next = maddr[UNIT_OFFSET_LSB+:UNIT_ADDRESS_WIDTH] + (1 as UNIT_ADDRESS_WIDTH); + return (maddr_next << UNIT_OFFSET_LSB) as CSRBUS_PKG::pzcorebus_maddr; + } + + function get_mdata( + mdata : input MEMBUS_INTERNAL_PKG::pzcorebus_mdata, + data_count: input logic , + ) -> CSRBUS_PKG::pzcorebus_mdata { + return mdata[data_count step $bits(CSRBUS_PKG::pzcorebus_mdata)]; + } + + function get_mdata_byteen( + mdata_byteen: input MEMBUS_INTERNAL_PKG::pzcorebus_mdata_byteen, + data_count : input logic , + ) -> CSRBUS_PKG::pzcorebus_mdata_byteen { + if !CSRBUS_PKG::BUS_CONFIG.use_byte_enable { + return '0; + } else if !MEMBUS_INTERNAL_PKG::BUS_CONFIG.use_byte_enable { + return '1; + } else { + return mdata_byteen[data_count step $bits(CSRBUS_PKG::pzcorebus_mdata_byteen)]; + } + } + + function is_write_data_inactive( + mdata_byteen: input MEMBUS_INTERNAL_PKG::pzcorebus_mdata_byteen, + data_count : input logic , + ) -> logic { + const STEP: u32 = CSRBUS_PKG::BUS_CONFIG.data_width / 8; + if !MEMBUS_PKG::BUS_CONFIG.use_byte_enable { + return false; + } else { + return mdata_byteen[data_count step STEP] == '0; + } + } + + function get_sresp_info( + mcmd : input MEMBUS_INTERNAL_PKG::pzcorebus_bundled_mcmd, + sideband_info: input pzcorebus_sideband_info , + ) -> pzcorebus_sresp_info { + var info: pzcorebus_sresp_info; + + case mcmd.mcmd { + pzcorebus_common_pkg::pzcorebus_mcmd::READ: { + info.sresp = pzcorebus_common_pkg::pzcorebus_sresp::RESPONSE_WITH_DATA; + info.ignore_response = false; + } + pzcorebus_common_pkg::pzcorebus_mcmd::WRITE , + pzcorebus_common_pkg::pzcorebus_mcmd::FULL_WRITE: { + info.sresp = pzcorebus_common_pkg::pzcorebus_sresp::RESPONSE; + info.ignore_response = sideband_info.force_np_write; + } + default: { + info.sresp = pzcorebus_common_pkg::pzcorebus_sresp::RESPONSE; + info.ignore_response = false; + } + } + info.sid = mcmd.mid; + info.uniten_offset = mcmd.maddr[UNIT_OFFSET_LSB+:UNITEN_COUNT_WIDTH]; + + return info; + } + +//-------------------------------------------------------------- +// Response path +//-------------------------------------------------------------- + inst u_sresp_info_fifo: $std::fifo #( + TYPE : pzcorebus_sresp_info, + DEPTH: SRESP_INFO_DEPTH , + )( + i_clk : i_clk , + i_rst : i_rst , + i_clear : false , + o_empty : info_fifo_empty, + o_almost_full: _ , + o_full : info_fifo_full , + o_word_count : _ , + i_push : info_fifo_push , + i_data : sresp_info[0] , + i_pop : info_fifo_pop , + o_data : sresp_info[1] , + ); + + inst u_sresp_count_fifo: $std::fifo #( + TYPE : MEMBUS_PKG::pzcorebus_mlength_unpacked, + DEPTH: SRESP_INFO_DEPTH , + )( + i_clk : i_clk , + i_rst : i_rst , + i_clear : false , + o_empty : sresp_count_empty, + o_almost_full: _ , + o_full : _ , + o_word_count : _ , + i_push : sresp_count_push , + i_data : sresp_count[0] , + i_pop : info_fifo_pop , + o_data : sresp_count[1] , + ); + + :g_sresp_path { + var sresp_done : logic<3> ; + var busy : logic ; + var length_count : MEMBUS_INTERNAL_PKG::pzcorebus_mlength_unpacked[2]; + var length_count_next : MEMBUS_INTERNAL_PKG::pzcorebus_mlength_unpacked ; + var uniten_count_end : logic<2, UNITEN_COUNT_WIDTH> ; + var uniten_count_start: logic<2, UNITEN_COUNT_WIDTH> ; + var uniten_count_next : logic ; + var data_count : logic ; + var data_count_last : logic ; + var sresp_valid : logic<3> ; + var sdata : MEMBUS_INTERNAL_PKG::pzcorebus_sdata ; + var serror : logic ; + + always_comb { + sresp_done[0] = csrbus_if.sresp_ack() && sresp_valid[1]; + sresp_done[1] = sresp_valid[2]; + sresp_done[2] = (!sresp_count_empty) && (sresp_count[1] == (0 as MEMBUS_PKG::pzcorebus_mlength_unpacked)); + info_fifo_pop = sresp_done != '0; + } + + always_ff { + if_reset { + busy = false; + } else if sresp_done != '0 { + busy = false; + } else if csrbus_if.sresp_ack() { + busy = true; + } + } + + always_comb { + if busy { + length_count[0] = length_count[1]; + uniten_count_end[0] = uniten_count_end[1]; + uniten_count_start[0] = uniten_count_start[1]; + } else { + length_count[0] = 0 as MEMBUS_PKG::pzcorebus_mlength_unpacked; + uniten_count_end[0] = sresp_info[1].uniten_offset; + uniten_count_start[0] = sresp_info[1].uniten_offset; + } + + length_count_next = length_count[0] + (1 as MEMBUS_PKG::pzcorebus_mlength_unpacked); + uniten_count_next = uniten_count_end[0] + (1 as UNITEN_COUNT_WIDTH); + data_count = uniten_count_end[0][0+:DATA_COUNT_WIDTH]; + data_count_last = data_count == '1; + } + + always_ff { + if_reset { + length_count[1] = 0 as MEMBUS_PKG::pzcorebus_mlength_unpacked; + uniten_count_end[1] = 0 as UNITEN_COUNT_WIDTH; + uniten_count_start[1] = 0 as UNITEN_COUNT_WIDTH; + } else if csrbus_if.sresp_ack() { + length_count[1] = length_count_next; + uniten_count_end[1] = uniten_count_next; + if slicer_if.sresp_valid { + uniten_count_start[1] = uniten_count_next; + } + } + } + + always_comb { + sresp_valid[0] = (sresp_info[1].sresp == pzcorebus_common_pkg::pzcorebus_sresp::RESPONSE_WITH_DATA) && data_count_last; + sresp_valid[1] = is_length_count_last(length_count_next, sresp_count_empty, sresp_count[1]); + sresp_valid[2] = is_length_count_last(length_count[0], sresp_count_empty, sresp_count[1]); + if info_fifo_empty { + csrbus_if.mresp_accept = false; + slicer_if.sresp_valid = false; + } else if sresp_info[1].ignore_response || (sresp_valid == '0) { + csrbus_if.mresp_accept = true; + slicer_if.sresp_valid = false; + } else { + csrbus_if.mresp_accept = slicer_if.mresp_accept; + slicer_if.sresp_valid = csrbus_if.sresp_valid || sresp_valid[2]; + } + + slicer_if.sresp = sresp_info[1].sresp; + slicer_if.sid = sresp_info[1].sid; + slicer_if.serror = csrbus_if.serror || serror; + slicer_if.sdata = sdata; + slicer_if.sinfo = '0; + slicer_if.sresp_uniten = get_sresp_uniten(uniten_count_start[0], uniten_count_end[0]); + slicer_if.sresp_last = if sresp_valid[2:1] != '0 ? '1 : '0; + } + + always_ff { + if_reset { + serror = false; + } else if slicer_if.sresp_ack() || (sresp_done != '0) { + serror = false; + } else if csrbus_if.sresp_ack() && csrbus_if.serror { + serror = true; + } + } + + for i in 0..MEMBUS_INTERNAL_PKG::BUS_CONFIG.data_size :g_sdata { + if (i + 1) == MEMBUS_INTERNAL_PKG::BUS_CONFIG.data_size :g { + always_comb { + sdata[i step MEMBUS_INTERNAL_PKG::BUS_CONFIG.unit_data_width] = csrbus_if.sdata; + } + } else { + var sdata_stored: logic; + var match : logic ; + + always_comb { + match = data_count == (i as DATA_COUNT_WIDTH); + if match { + sdata[i step MEMBUS_INTERNAL_PKG::BUS_CONFIG.unit_data_width] = csrbus_if.sdata; + } else { + sdata[i step MEMBUS_INTERNAL_PKG::BUS_CONFIG.unit_data_width] = sdata_stored; + } + } + + always_ff { + if csrbus_if.sresp_ack() && match { + sdata_stored = csrbus_if.sdata; + } + } + } + } + } + + function is_length_count_last( + length_count: input MEMBUS_INTERNAL_PKG::pzcorebus_mlength_unpacked, + empty : input logic , + sresp_count : input MEMBUS_INTERNAL_PKG::pzcorebus_mlength_unpacked, + ) -> logic { + return (!empty) && (sresp_count >: (0 as MEMBUS_INTERNAL_PKG::pzcorebus_mlength_unpacked)) && (length_count == sresp_count); + } + + function get_sresp_uniten( + count_start: input logic, + count_end : input logic, + ) -> MEMBUS_INTERNAL_PKG::pzcorebus_sresp_uniten { + var uniten: MEMBUS_INTERNAL_PKG::pzcorebus_sresp_uniten; + + if pzcorebus_common_pkg::is_mem_h_profile(MEMBUS_INTERNAL_PKG::BUS_CONFIG) { + for i in 0..MEMBUS_INTERNAL_PKG::BUS_CONFIG.data_size { + uniten[i] = ((i as UNITEN_COUNT_WIDTH) >= count_start) && ((i as UNITEN_COUNT_WIDTH) <= count_end); + } + } else { + uniten = '0; + } + + return uniten; + } + +//-------------------------------------------------------------- +// Buffer +//-------------------------------------------------------------- + inst u_buffer: pzcorebus_csrbus_adapter_buffer:: #( + ENTRIES : MAX_NP_REUQESTS , + MASTER_SLICER_MCMD : MASTER_SLICER_MCMD , + MASTER_SLICER_SRESP: MASTER_SLICER_SRESP, + )( + i_clk : i_clk , + i_rst : i_rst , + i_base_id : i_base_id , + i_wait_for_all_sresp: sideband_info.wait_for_all_sresp, + slave_if : csrbus_if , + master_if : csrbus_master_if , + ); +} diff --git a/veryl/pzcorebus_csrbus_adapter/pzcorebus_csrbus_adapter_buffer.veryl b/veryl/pzcorebus_csrbus_adapter/pzcorebus_csrbus_adapter_buffer.veryl new file mode 100644 index 0000000..75782bc --- /dev/null +++ b/veryl/pzcorebus_csrbus_adapter/pzcorebus_csrbus_adapter_buffer.veryl @@ -0,0 +1,167 @@ +//======================================== +// +// Copyright (c) 2026 PEZY Computing, K.K. +// +//======================================== +module pzcorebus_csrbus_adapter_buffer::< + CSRBUS_PKG: pzcorebus_proto_pkg, +> #( + param ENTRIES : u32 = 2 , + param MASTER_SLICER_MCMD : bbool = true, + param MASTER_SLICER_SRESP: bbool = true, +)( + i_clk : input clock , + i_rst : input reset , + i_base_id : input CSRBUS_PKG::pzcorebus_id , + i_wait_for_all_sresp: input logic , + slave_if : modport pzcorebus_if::::slave , + master_if : modport pzcorebus_if::::master, +) { + const INDEX_WIDTH: u32 = $clog2(ENTRIES); + + struct pzcorebus_sresp_entry { + busy : logic , + sresp_valid: logic , + serror : logic , + sdata : CSRBUS_PKG::pzcorebus_data, + } + + var sresp_entries: pzcorebus_sresp_entry[ENTRIES]; + inst bus_if : pzcorebus_if:: ; + +//-------------------------------------------------------------- +// Request +//-------------------------------------------------------------- + var mcmd_index: logic ; + var mcmd_ready: logic<2> ; + var mcmd : CSRBUS_PKG::pzcorebus_bundled_mcmd; + + always_comb { + mcmd_ready[0] = slave_if.is_mcmd_posted(); + mcmd_ready[1] = get_np_ready(mcmd_index, sresp_entries, i_wait_for_all_sresp); + if mcmd_ready != '0 { + slave_if.scmd_accept = bus_if.scmd_accept; + bus_if.mcmd_valid = slave_if.mcmd_valid; + } else { + slave_if.scmd_accept = false; + bus_if.mcmd_valid = false; + } + + mcmd = slave_if.get_mcmd(); + mcmd.mid = i_base_id | (mcmd_index as CSRBUS_PKG::pzcorebus_id); + bus_if.put_mcmd(mcmd); + } + + always_comb { + slave_if.sdata_accept = false; + bus_if.mdata_valid = false; + bus_if.mdata_last = false; + } + + always_ff { + if_reset { + mcmd_index = 0 as INDEX_WIDTH; + } else if slave_if.mcmd_non_posted_ack() { + if mcmd_index == ((ENTRIES - 1) as INDEX_WIDTH) { + mcmd_index = 0 as INDEX_WIDTH; + } else { + mcmd_index += (1 as INDEX_WIDTH); + } + } + } + + function get_np_ready( + index : input logic , + entires : input pzcorebus_sresp_entry[ENTRIES], + wait_for_all_sresp: input logic , + ) -> logic { + var busy: logic; + + for i in 0..ENTRIES { + busy[i] = entires[i].busy; + } + + return (!entires[index].busy) && ((!wait_for_all_sresp) || (busy == '0)); + } + +//-------------------------------------------------------------- +// Response +//-------------------------------------------------------------- + var sresp_entry: pzcorebus_sresp_entry; + var sresp_index: logic ; + + always_comb { + sresp_entry = sresp_entries[sresp_index]; + slave_if.sresp_valid = sresp_entry.sresp_valid; + slave_if.sid = 0 as CSRBUS_PKG::pzcorebus_id; + slave_if.sresp = 0 as CSRBUS_PKG::pzcorebus_sresp; + slave_if.serror = sresp_entry.serror; + slave_if.sdata = sresp_entry.sdata; + slave_if.sinfo = '0; + slave_if.sresp_uniten = '0; + slave_if.sresp_last = '0; + } + + always_ff { + if_reset { + sresp_index = 0 as INDEX_WIDTH; + } else if slave_if.sresp_ack() { + if sresp_index == ((ENTRIES - 1) as INDEX_WIDTH) { + sresp_index = 0 as INDEX_WIDTH; + } else { + sresp_index += (1 as INDEX_WIDTH); + } + } + } + +//-------------------------------------------------------------- +// Response entry +//-------------------------------------------------------------- + always_comb { + bus_if.mresp_accept = true; + } + + for i in 0..ENTRIES :g_sresp_entry { + const INDEX: bit = i as INDEX_WIDTH; + + var init : logic; + var fill : logic; + var clear: logic; + + always_comb { + init = bus_if.mcmd_non_posted_ack() && (mcmd_index == INDEX); + fill = bus_if.sresp_ack() && ((bus_if.sid as INDEX_WIDTH) == INDEX); + clear = slave_if.sresp_ack() && (sresp_index == INDEX); + } + + always_ff { + if_reset { + sresp_entries[i] = '0; + } else if init { + sresp_entries[i].busy = true; + } else if fill { + sresp_entries[i].sresp_valid = true; + sresp_entries[i].serror = bus_if.serror; + sresp_entries[i].sdata = bus_if.sdata; + } else if clear { + sresp_entries[i].busy = false; + sresp_entries[i].sresp_valid = false; + } + } + + let _busy: logic = sresp_entries[i].busy; + } + +//-------------------------------------------------------------- +// Slicer +//-------------------------------------------------------------- + inst u_slicer: pzcorebus_slicer:: #( + MCMD_VALID : MASTER_SLICER_MCMD , + SRESP_VALID: MASTER_SLICER_SRESP, + )( + i_clk : i_clk , + i_rst : i_rst , + slave_if : bus_if , + master_if: master_if, + ); +} diff --git a/veryl/pzcorebus_debug/pzcorebus_debug_mcmd_counter.veryl b/veryl/pzcorebus_debug/pzcorebus_debug_mcmd_counter.veryl new file mode 100644 index 0000000..441f32e --- /dev/null +++ b/veryl/pzcorebus_debug/pzcorebus_debug_mcmd_counter.veryl @@ -0,0 +1,42 @@ +//======================================== +// +// Copyright (c) 2026 PEZY Computing, K.K. +// +//======================================== +pub module pzcorebus_debug_mcmd_counter:: #( + param COUNT_WIDTH: u32 = 16, + param TARGET_MCMD: bit = '0, +)( + i_clk : input clock , + i_rst : input reset , + i_enable : input logic , + i_clear : input logic , + corebus_if: modport pzcorebus_if::::monitor, + o_count : output logic , +) { + import pzcorebus_debug_pkg::*; + + var count: logic; + var up : logic ; + + always_comb { + o_count = count; + } + + always_comb { + up = + i_enable + && corebus_if.mcmd_ack() + && is_target_mcmd(corebus_if.mcmd, TARGET_MCMD); + } + + always_ff { + if_reset { + count = 0 as COUNT_WIDTH; + } else if i_clear { + count = 0 as COUNT_WIDTH; + } else if up { + count += 1 as COUNT_WIDTH; + } + } +} diff --git a/veryl/pzcorebus_debug/pzcorebus_debug_mlengh_counter.veryl b/veryl/pzcorebus_debug/pzcorebus_debug_mlengh_counter.veryl new file mode 100644 index 0000000..38762c1 --- /dev/null +++ b/veryl/pzcorebus_debug/pzcorebus_debug_mlengh_counter.veryl @@ -0,0 +1,46 @@ +//======================================== +// +// Copyright (c) 2025 PEZY Computing, K.K. +// +//======================================== +pub module pzcorebus_debug_mlengh_counter:: #( + param COUNT_WIDTH: u32 = 16 , + param TARGET_MCMD: bit = '0 , + param BURST_COUNT: bbool = false, +)( + i_clk : input clock , + i_rst : input reset , + i_enable : input logic , + i_clear : input logic , + corebus_if: modport pzcorebus_if::::monitor, + o_count : output logic , +) { + import pzcorebus_debug_pkg::*; + + var count : logic; + var target_mcmd_ack: logic; + + always_comb { + o_count = count; + } + + always_comb { + target_mcmd_ack = + corebus_if.mcmd_ack() + && pzcorebus_debug_pkg::is_target_mcmd(corebus_if.mcmd, TARGET_MCMD); + } + + always_ff { + if_reset { + count = 0 as COUNT_WIDTH; + } else if i_clear { + count = 0 as COUNT_WIDTH; + } else if i_enable && target_mcmd_ack { + if BURST_COUNT { + count += (corebus_if.get_mburst_length() as COUNT_WIDTH); + } else { + count += (corebus_if.get_mlength_unpacked() as COUNT_WIDTH); + } + } + } +} diff --git a/veryl/pzcorebus_debug/pzcorebus_debug_pkg.veryl b/veryl/pzcorebus_debug/pzcorebus_debug_pkg.veryl new file mode 100644 index 0000000..af51491 --- /dev/null +++ b/veryl/pzcorebus_debug/pzcorebus_debug_pkg.veryl @@ -0,0 +1,61 @@ +//======================================== +// +// Copyright (c) 2025 PEZY Computing, K.K. +// +//======================================== +pub package pzcorebus_debug_pkg { + import pzcorebus_common_pkg::pzcorebus_mcmd; + import pzcorebus_common_pkg::pzcorebus_sresp; + + #[enum_encoding(onehot)] + enum pzcorebus_debug_target_mcmd { + READ , + WRITE , + WRITE_NP , + FULL_WRITE , + FULL_WRITE_NP, + BROADCAST , + ATOMIC , + ATOMIC_NP , + MESSAGE , + MESSAGE_NP , + } + + #[enum_encoding(onehot)] + enum pzcorebus_debug_target_sresp { + RESPONSE , + RESPONSE_WITH_DATA, + } + + const TARGET_MCMD_WIDTH : u16 = $bits(pzcorebus_debug_target_mcmd); + const TARGET_SRESP_WIDTH: u16 = $bits(pzcorebus_debug_target_sresp); + + function is_target_mcmd( + mcmd : input pzcorebus_mcmd , + target_mcmd: input bit, + ) -> logic { + case mcmd { + pzcorebus_mcmd::READ : return (target_mcmd & pzcorebus_debug_target_mcmd::READ ) != '0; + pzcorebus_mcmd::WRITE : return (target_mcmd & pzcorebus_debug_target_mcmd::WRITE ) != '0; + pzcorebus_mcmd::WRITE_NP : return (target_mcmd & pzcorebus_debug_target_mcmd::WRITE_NP ) != '0; + pzcorebus_mcmd::FULL_WRITE : return (target_mcmd & pzcorebus_debug_target_mcmd::FULL_WRITE ) != '0; + pzcorebus_mcmd::FULL_WRITE_NP: return (target_mcmd & pzcorebus_debug_target_mcmd::FULL_WRITE_NP) != '0; + pzcorebus_mcmd::BROADCAST : return (target_mcmd & pzcorebus_debug_target_mcmd::BROADCAST ) != '0; + pzcorebus_mcmd::ATOMIC : return (target_mcmd & pzcorebus_debug_target_mcmd::ATOMIC ) != '0; + pzcorebus_mcmd::ATOMIC_NP : return (target_mcmd & pzcorebus_debug_target_mcmd::ATOMIC_NP ) != '0; + pzcorebus_mcmd::MESSAGE : return (target_mcmd & pzcorebus_debug_target_mcmd::MESSAGE ) != '0; + pzcorebus_mcmd::MESSAGE_NP : return (target_mcmd & pzcorebus_debug_target_mcmd::MESSAGE_NP ) != '0; + default: return false; + } + } + + function is_target_sresp( + sresp : input pzcorebus_sresp , + target_sresp: input bit, + ) -> logic { + case sresp { + pzcorebus_sresp::RESPONSE: return (target_sresp & pzcorebus_debug_target_sresp::RESPONSE ) != '0; + default : return (target_sresp & pzcorebus_debug_target_sresp::RESPONSE_WITH_DATA) != '0; + } + } +} diff --git a/veryl/pzcorebus_debug/pzcorebus_debug_sresp_counter.veryl b/veryl/pzcorebus_debug/pzcorebus_debug_sresp_counter.veryl new file mode 100644 index 0000000..d1964ae --- /dev/null +++ b/veryl/pzcorebus_debug/pzcorebus_debug_sresp_counter.veryl @@ -0,0 +1,45 @@ +//======================================== +// +// Copyright (c) 2025 PEZY Computing, K.K. +// +//======================================== +pub module pzcorebus_debug_sresp_counter:: #( + param COUNT_WIDTH : u32 = 16 , + param TARGET_SRESP: bit = '1 , + param ERROR_ONLY : bbool = false, + param LAST_ONLY : bbool = false, +)( + i_clk : input clock , + i_rst : input reset , + i_enable : input logic , + i_clear : input logic , + corebus_if: modport pzcorebus_if::::monitor, + o_count : output logic , +) { + import pzcorebus_debug_pkg::*; + + var count : logic; + var target_sresp_ack: logic; + + always_comb { + o_count = count; + } + + always_comb { + target_sresp_ack = + corebus_if.sresp_ack() + && is_target_sresp(corebus_if.sresp, TARGET_SRESP) + && (if ERROR_ONLY ? corebus_if.serror : true) + && (if LAST_ONLY ? corebus_if.sresp_last[0] : true); + } + + always_ff { + if_reset { + count = 0 as COUNT_WIDTH; + } else if i_clear { + count = 0 as COUNT_WIDTH; + } else if i_enable && target_sresp_ack { + count += (1 as COUNT_WIDTH); + } + } +} diff --git a/veryl/pzcorebus_downsizer/pzcorebus_downsizer.veryl b/veryl/pzcorebus_downsizer/pzcorebus_downsizer.veryl new file mode 100644 index 0000000..9a740b8 --- /dev/null +++ b/veryl/pzcorebus_downsizer/pzcorebus_downsizer.veryl @@ -0,0 +1,69 @@ +//======================================== +// +// Copyright (c) 2026 PEZY Computing, K.K. +// +//======================================== +pub module pzcorebus_downsizer::< + SLAVE_PKG : pzcorebus_proto_pkg, + MASTER_PKG: pzcorebus_proto_pkg, +> #( + param SLAVE_FIFO : bbool = false, + param SLAVE_FIFO_MCMD_DEPTH : u32 = 2 , + param SLAVE_FIFO_MDATA_DEPTH : u32 = 2 , + param SLAVE_FIFO_SRESP_DEPTH : u32 = 2 , + param MASTER_FIFO : bbool = false, + param MASTER_FIFO_MCMD_DEPTH : u32 = 2 , + param MASTER_FIFO_MDATA_DEPTH : u32 = 2 , + param MASTER_FIFO_SRESP_DEPTH : u32 = 2 , + param ALLIGNED_ACCESS_ONLY : bbool = false, +)( + i_clk : input clock , + i_rst : input reset , + slave_if : modport pzcorebus_if::::slave , + master_if: modport pzcorebus_if::::master, +) { + inst aligner_if: pzcorebus_if:: ; + inst fifo_if : pzcorebus_if::; + + inst u_aligner: pzcorebus_mreq_aligner:: #( + SLAVE_FIFO : SLAVE_FIFO , + SLAVE_FIFO_MCMD_DEPTH : SLAVE_FIFO_MCMD_DEPTH , + SLAVE_FIFO_MDATA_DEPTH: SLAVE_FIFO_MDATA_DEPTH, + SLAVE_FIFO_SRESP_DEPTH: SLAVE_FIFO_SRESP_DEPTH, + )( + i_clk : i_clk , + i_rst : i_rst , + slave_if : slave_if , + master_if: aligner_if, + ); + + inst u_request_path: pzcorebus_downsizer_request_path:: #( + ALLIGNED_ACCESS_ONLY: ALLIGNED_ACCESS_ONLY, + )( + i_clk : i_clk , + i_rst : i_rst , + slave_if : aligner_if, + master_if: fifo_if , + ); + + inst u_response_path: pzcorebus_downsizer_response_path:: ( + i_clk : i_clk , + i_rst : i_rst , + slave_if : aligner_if, + master_if: fifo_if , + ); + + inst u_fifo: pzcorebus_fifo:: #( + MCMD_DEPTH : MASTER_FIFO_MCMD_DEPTH , + MCMD_VALID : MASTER_FIFO , + MDATA_DEPTH : MASTER_FIFO_MDATA_DEPTH, + MDATA_VALID : MASTER_FIFO , + SRESP_DEPTH : MASTER_FIFO_SRESP_DEPTH, + SRESP_VALID : MASTER_FIFO , + )( + i_clk : i_clk , + i_rst : i_rst , + slave_if : fifo_if , + master_if: master_if, + ); +} diff --git a/veryl/pzcorebus_downsizer/pzcorebus_downsizer_request_path.veryl b/veryl/pzcorebus_downsizer/pzcorebus_downsizer_request_path.veryl new file mode 100644 index 0000000..699159f --- /dev/null +++ b/veryl/pzcorebus_downsizer/pzcorebus_downsizer_request_path.veryl @@ -0,0 +1,122 @@ +//======================================== +// +// Copyright (c) 2026 PEZY Computing, K.K. +// +//======================================== +module pzcorebus_downsizer_request_path::< + SLAVE_PKG : pzcorebus_proto_pkg, + MASTER_PKG: pzcorebus_proto_pkg, +> #( + param ALLIGNED_ACCESS_ONLY: bbool = false, +)( + i_clk : input clock , + i_rst : input reset , + slave_if : modport pzcorebus_if::::slave_mreq , + master_if: modport pzcorebus_if::::master_mreq, +) { + const CONVERSION_RATIO: u32 = SLAVE_PKG::BUS_CONFIG.data_width / MASTER_PKG::BUS_CONFIG.data_width; + const DATA_COUNT_WIDTH: u32 = $clog2(CONVERSION_RATIO) ; + const DATA_SIZE : u32 = MASTER_PKG::BUS_CONFIG.data_size; + + var mlength_count: SLAVE_PKG::pzcorebus_mlength_unpacked<2>; + var mdata_count : logic<2, DATA_COUNT_WIDTH> ; + var mdata_busy : logic ; + + always_ff { + if_reset { + mdata_busy = false; + } else if slave_if.mdata_last_ack() { + mdata_busy = false; + } else if master_if.mdata_ack() { + mdata_busy = true; + } + } + + always_comb { + if slave_if.mcmd_valid && (!mdata_busy) { + mlength_count[0] = get_initial_mlength_count(slave_if.get_mcmd()); + mdata_count[0] = get_initial_mdata_count(slave_if.get_mcmd()); + } else { + mlength_count[0] = mlength_count[1]; + mdata_count[0] = mdata_count[1]; + } + } + + always_ff { + if_reset { + mlength_count[1] = 0 as SLAVE_PKG::pzcorebus_mlength_unpacked; + mdata_count[1] = 0 as DATA_COUNT_WIDTH; + } else if master_if.mdata_ack() { + mlength_count[1] = mlength_count[0] - (DATA_SIZE as SLAVE_PKG::pzcorebus_mlength_unpacked); + mdata_count[1] = mdata_count[1] + (1 as DATA_COUNT_WIDTH); + } else if slave_if.mcmd_with_data_ack() { + mlength_count[1] = mlength_count[0]; + mdata_count[1] = mdata_count[0]; + } + } + + function get_initial_mlength_count( + mcmd: input SLAVE_PKG::pzcorebus_bundled_mcmd, + ) -> SLAVE_PKG::pzcorebus_mlength_unpacked { + if ALLIGNED_ACCESS_ONLY { + return pzcorebus_utils_pkg::::get_mlength_unpacked(mcmd.mcmd, mcmd.mlength); + } else { + return pzcorebus_utils_pkg::::get_mlength_aligned(mcmd.mcmd, mcmd.maddr, mcmd.mlength); + } + } + + function get_initial_mdata_count( + mcmd: input SLAVE_PKG::pzcorebus_bundled_mcmd, + ) -> logic { + const LSB: u32 = $clog2(MASTER_PKG::BUS_CONFIG.data_width / 8); + + if ALLIGNED_ACCESS_ONLY + || pzcorebus_utils_pkg::::is_mcmd_atomic(mcmd.mcmd) + || pzcorebus_utils_pkg::::is_mcmd_message(mcmd.mcmd) + { + return 0 as DATA_COUNT_WIDTH; + } else { + return mcmd.maddr[LSB+:DATA_COUNT_WIDTH]; + } + } + + always_comb { + slave_if.scmd_accept = master_if.scmd_accept; + master_if.mcmd_valid = slave_if.mcmd_valid; + master_if.mcmd = slave_if.mcmd; + master_if.mid = slave_if.mid; + master_if.maddr = slave_if.maddr; + master_if.mlength = slave_if.mlength; + master_if.mparam = slave_if.mparam; + master_if.minfo = slave_if.minfo; + } + + always_comb { + if mlength_count[0] <= (DATA_SIZE as SLAVE_PKG::pzcorebus_mlength_unpacked) || mdata_count[0] == '1 { + slave_if.sdata_accept = master_if.sdata_accept; + master_if.mdata_valid = slave_if.mdata_valid; + master_if.mdata_last = slave_if.mdata_last; + } else { + slave_if.sdata_accept = false; + master_if.mdata_valid = slave_if.mdata_valid; + master_if.mdata_last = false; + } + + master_if.mdata = get_mdata(slave_if.mdata, mdata_count[0]); + master_if.mdata_byteen = get_mdata_byteen(slave_if.mdata_byteen, mdata_count[0]); + } + + function get_mdata( + mdata : input MASTER_PKG::pzcorebus_mdata, + mdata_count: input logic , + ) -> MASTER_PKG::pzcorebus_mdata { + return mdata[mdata_count]; + } + + function get_mdata_byteen( + mdata_byteen: input MASTER_PKG::pzcorebus_mdata_byteen, + mdata_count : input logic , + ) -> MASTER_PKG::pzcorebus_mdata_byteen { + return mdata_byteen[mdata_count]; + } +} diff --git a/veryl/pzcorebus_downsizer/pzcorebus_downsizer_response_path.veryl b/veryl/pzcorebus_downsizer/pzcorebus_downsizer_response_path.veryl new file mode 100644 index 0000000..1cd21ed --- /dev/null +++ b/veryl/pzcorebus_downsizer/pzcorebus_downsizer_response_path.veryl @@ -0,0 +1,137 @@ +//======================================== +// +// Copyright (c) 2026 PEZY Computing, K.K. +// +//======================================== +module pzcorebus_downsizer_response_path::< + SLAVE_PKG : pzcorebus_proto_pkg, + MASTER_PKG: pzcorebus_proto_pkg, +> ( + i_clk : input clock , + i_rst : input reset , + slave_if : modport pzcorebus_if::::slave_sresp , + master_if: modport pzcorebus_if::::master_sresp, +){ + const UNIT_WIDTH : u32 = SLAVE_PKG::BUS_CONFIG.unit_data_width; + const MAX_DATA_SIZE : u32 = SLAVE_PKG::BUS_CONFIG.max_data_size ; + const SLAVE_DATA_SIZE : u32 = SLAVE_PKG::BUS_CONFIG.data_size ; + const MASTER_DATA_SIZE: u32 = MASTER_PKG::BUS_CONFIG.data_size ; + + var unit_enable : logic ; + var tail_unit_enable: logic ; + var sresp_busy : logic ; + var serror : logic<2> ; + var sdata : logic ; + var sinfo : SLAVE_PKG::pzcorebus_sinfo<2> ; + var sresp_uniten : SLAVE_PKG::pzcorebus_sresp_uniten<2>; + + always_comb { + unit_enable = get_unit_enable(master_if.sresp_uniten); + tail_unit_enable = unit_enable[msb]; + } + + function get_unit_enable( + sresp_uniten: input MASTER_PKG::pzcorebus_sresp_uniten, + ) -> logic { + var unit_enable: logic; + + unit_enable = '0; + for i in 0..(MAX_DATA_SIZE / SLAVE_DATA_SIZE) { + for j in 0..SLAVE_DATA_SIZE { + unit_enable[j] = unit_enable[j] || sresp_uniten[i * SLAVE_DATA_SIZE + j]; + } + } + + return unit_enable; + } + + always_ff { + if_reset { + sresp_busy = false; + } else if slave_if.sresp_ack() { + sresp_busy = false; + } else if master_if.sresp_ack() { + sresp_busy = true; + } + } + + always_comb { + serror[0] = serror[1] | master_if.serror; + sresp_uniten[0] = sresp_uniten[1] | master_if.sresp_uniten; + } + + always_ff { + if_reset { + serror[1] = '0; + sresp_uniten[1] = '0; + } else if slave_if.sresp_ack() { + serror[1] = '0; + sresp_uniten[1] = '0; + } else if master_if.sresp_ack() { + serror[1] = serror[0]; + sresp_uniten[1] = sresp_uniten[0]; + } + } + + if SLAVE_PKG::BUS_CONFIG.response_info_width >: 0 :g_sinfo { + always_comb { + sinfo[0] = if !sresp_busy ? master_if.sinfo : sinfo[1]; + } + + always_ff { + if_reset { + sinfo[1] = '0; + } else if (!sresp_busy) && master_if.sresp_ack() { + sinfo[1] = sinfo[0]; + } + } + } + + for i in 0..SLAVE_DATA_SIZE :g_sdata { + const LSB: u32 = UNIT_WIDTH * ((i % MASTER_DATA_SIZE) + 0) - 0; + const MSB: u32 = UNIT_WIDTH * ((i % MASTER_DATA_SIZE) + 1) - 1; + + if (i + 1) == SLAVE_DATA_SIZE :g { + always_comb { + sdata[i] = master_if.sdata[MSB:LSB]; + } + } else { + var sdata_latched: logic; + + always_comb { + if unit_enable[i] { + sdata[i] = master_if.sdata[MSB:LSB]; + } else { + sdata[i] = sdata_latched; + } + } + + always_ff { + if unit_enable[i] && master_if.sresp_ack() { + sdata_latched = master_if.sdata[MSB:LSB]; + } + } + } + } + + always_comb { + if master_if.is_sresp_no_data() + || master_if.sresp_last != '0 + || tail_unit_enable + { + master_if.mresp_accept = slave_if.mresp_accept; + slave_if.sresp_valid = master_if.sresp_valid; + } else { + master_if.mresp_accept = true; + slave_if.sresp_valid = false; + } + + slave_if.sresp = master_if.sresp; + slave_if.sid = master_if.sid; + slave_if.serror = serror[0]; + slave_if.sdata = sdata; + slave_if.sinfo = sinfo[0]; + slave_if.sresp_uniten = sresp_uniten[0]; + slave_if.sresp_last = master_if.sresp_last; + } +} diff --git a/veryl/pzcorebus_dummy/pzcorebus_dummy_master.veryl b/veryl/pzcorebus_dummy/pzcorebus_dummy_master.veryl new file mode 100644 index 0000000..8433c6e --- /dev/null +++ b/veryl/pzcorebus_dummy/pzcorebus_dummy_master.veryl @@ -0,0 +1,18 @@ +pub module pzcorebus_dummy_master:: ( + master_if: modport pzcorebus_if::::master, +) { + always_comb { + master_if.mcmd_valid = false; + master_if.mcmd = 0 as PKG::pzcorebus_mcmd; + master_if.mid = '0; + master_if.maddr = '0; + master_if.mlength = '0; + master_if.mparam = '0; + master_if.minfo = '0; + master_if.mdata_valid = false; + master_if.mdata = '0; + master_if.mdata_byteen = '0; + master_if.mdata_last = '0; + master_if.mresp_accept = false; + } +} diff --git a/veryl/pzcorebus_dummy/pzcorebus_dummy_slave.veryl b/veryl/pzcorebus_dummy/pzcorebus_dummy_slave.veryl new file mode 100644 index 0000000..371a40e --- /dev/null +++ b/veryl/pzcorebus_dummy/pzcorebus_dummy_slave.veryl @@ -0,0 +1,257 @@ +//======================================== +// +// Copyright (c) 2026 PEZY Computing, K.K. +// +//======================================== +pub module pzcorebus_dummy_slave:: #( + param TIE_OFF : bbool = false, + param SERROR : bbool = true , + param CUSTOM_SDATA : bbool = false, + param SDATA : PKG::pzcorebus_sdata = '0 , + param REPORT_WARNING: bbool = true , +)( + i_clk : input clock , + i_rst : input reset , + slave_if: modport pzcorebus_if::::slave, +) { + import pzcorebus_common_pkg::*; + + const MEM_L_PROFILE: bbool = is_mem_l_profile(PKG::BUS_CONFIG); + const MEM_H_PROFILE: bbool = is_mem_h_profile(PKG::BUS_CONFIG); + + if TIE_OFF :g { + always_comb { + slave_if.scmd_accept = true; + slave_if.sdata_accept = true; + slave_if.sresp_valid = false; + slave_if.sresp = 0 as pzcorebus_sresp; + slave_if.sid = '0; + slave_if.serror = '0; + slave_if.sdata = '0; + slave_if.sinfo = '0; + slave_if.sresp_uniten = '0; + slave_if.sresp_last = '0; + } + } else { + inst bus_if: pzcorebus_if::; + + var scmd_accept : logic ; + var sdata_accept: logic ; + var sresp_valid : logic<2> ; + var sresp : pzcorebus_sresp ; + var sid : PKG::pzcorebus_sid ; + var serror : logic ; + var sresp_uniten: PKG::pzcorebus_sresp_uniten; + var sresp_last : PKG::pzcorebus_sresp_last ; + + inst u_slicer: pzcorebus_slicer:: #( + FULL_BANDWIDTH: is_mem_profile(PKG::BUS_CONFIG), + MCMD_VALID : false , + MDATA_VALID : false , + SRESP_VALID : true , + )( + i_clk : i_clk , + i_rst : i_rst , + slave_if : slave_if, + master_if: bus_if , + ); + + always_comb { + bus_if.scmd_accept = scmd_accept; + bus_if.sdata_accept = sdata_accept; + bus_if.sresp_valid = sresp_valid[0] && sresp_valid[1]; + bus_if.sresp = sresp; + bus_if.sid = sid; + bus_if.serror = serror; + bus_if.sdata = get_sdata(); + bus_if.sinfo = '0; + bus_if.sresp_uniten = sresp_uniten; + bus_if.sresp_last = sresp_last; + } + + always_ff { + if_reset { + sid = '0; + sresp = 0 as pzcorebus_sresp; + serror = false; + } else if bus_if.mcmd_non_posted_ack() { + sid = bus_if.mid; + case bus_if.mcmd_kind() { + pzcorebus_mcmd_kind::READ , + pzcorebus_mcmd_kind::ATOMIC: sresp = pzcorebus_sresp::RESPONSE_WITH_DATA; + default : sresp = pzcorebus_sresp::RESPONSE; + } + case bus_if.mcmd_kind() { + pzcorebus_mcmd_kind::BROADCAST: serror = false; + default : serror = SERROR; + } + } + } + + if MEM_L_PROFILE || MEM_H_PROFILE :g_membus { + always_ff { + if_reset { + scmd_accept = true; + } else if bus_if.sresp_last_ack() { + scmd_accept = true; + } else if bus_if.mdata_last_ack() { + scmd_accept = !sresp_valid[0]; + } else if bus_if.mcmd_ack() { + scmd_accept = bus_if.mcmd == pzcorebus_mcmd::MESSAGE; + } + } + + always_ff { + if_reset { + sdata_accept = false; + } else if bus_if.mdata_last_ack() { + sdata_accept = false; + } else if bus_if.mcmd_with_data_ack() { + sdata_accept = true; + } + } + + always_ff { + if_reset { + sresp_valid[0] = false; + sresp_valid[1] = false; + } else if bus_if.sresp_last_ack() { + sresp_valid[0] = false; + sresp_valid[1] = false; + } else if bus_if.mcmd_non_posted_ack() { + sresp_valid[0] = true; + sresp_valid[1] = bus_if.is_mcmd_with_response_data(); + } else if bus_if.mdata_last_ack() { + sresp_valid[0] = sresp_valid[0]; + sresp_valid[1] = sresp_valid[0]; + } + } + + if MEM_L_PROFILE :g_membus_l { + var sresp_count: PKG::pzcorebus_mburst_length; + + always_comb { + sresp_uniten = '0; + sresp_last = sresp_count == (1 as PKG::pzcorebus_mburst_length); + } + + always_ff { + if_reset { + sresp_count = 0 as PKG::pzcorebus_mburst_length; + } else if bus_if.mcmd_non_posted_ack() { + sresp_count = bus_if.get_mburst_length(); + } else if bus_if.sresp_ack() { + sresp_count -= (1 as PKG::pzcorebus_mburst_length); + } + } + } else :g_membus_h { + var mlength : PKG::pzcorebus_mlength_unpacked; + var sresp_size : PKG::pzcorebus_sresp_size ; + var sresp_count : PKG::pzcorebus_mlength_unpacked; + var sresp_count_next : PKG::pzcorebus_mlength_unpacked; + var sresp_offset : PKG::pzcorebus_sresp_offset ; + var sresp_offset_next: PKG::pzcorebus_sresp_offset ; + + always_comb { + sresp_uniten = get_sresp_uniten(sresp_offset, sresp_size); + sresp_last = if sresp_count_next >= mlength ? '1 : '0; + } + + always_comb { + sresp_size = get_sresp_size(mlength, sresp_count, sresp_offset); + sresp_count_next = sresp_count + (sresp_size as PKG::pzcorebus_mlength_unpacked); + sresp_offset_next = sresp_offset + (sresp_size as PKG::pzcorebus_sresp_offset); + } + + always_ff { + if_reset { + mlength = 0 as PKG::pzcorebus_mlength_unpacked; + } else if bus_if.mcmd_non_posted_ack() { + mlength = bus_if.get_sresp_length(); + } + } + + always_ff { + if_reset { + sresp_count = 0 as PKG::pzcorebus_mlength_unpacked; + sresp_offset = 0 as PKG::pzcorebus_sresp_offset; + } else if bus_if.mcmd_non_posted_ack() { + sresp_count = 0 as PKG::pzcorebus_mlength_unpacked; + sresp_offset = bus_if.get_sresp_offset(); + } else if bus_if.sresp_ack() { + sresp_count = sresp_count_next; + sresp_offset = sresp_offset_next; + } + } + } + } else :g_csrbus { + always_comb { + scmd_accept = !sresp_valid[0]; + sdata_accept = false; + sresp_valid[1] = true; + sresp_uniten = '0; + sresp_last = '0; + } + + always_ff { + if_reset { + sresp_valid[0] = false; + } else if bus_if.sresp_ack() { + sresp_valid[0] = false; + } else if bus_if.mcmd_non_posted_ack() { + sresp_valid[0] = true; + } + } + } + } + + function get_sdata() -> PKG::pzcorebus_sdata { + if CUSTOM_SDATA { + return SDATA; + } else if MEM_L_PROFILE || MEM_H_PROFILE { + return {32'hdead_beaf repeat (PKG::BUS_CONFIG.data_width / 32)} as PKG::pzcorebus_sdata; + } else { + return {32'hdead_dead repeat (PKG::BUS_CONFIG.data_width / 32)} as PKG::pzcorebus_sdata; + } + } + + function get_sresp_size( + mlength : input PKG::pzcorebus_mlength_unpacked, + sresp_count : input PKG::pzcorebus_mlength_unpacked, + sresp_offset: input PKG::pzcorebus_sresp_offset , + ) -> PKG::pzcorebus_sresp_size { + const DATA_SIZE : u16 = PKG::BUS_CONFIG.data_size; + const OFFSET_WIDTH: u16 = pzcorebus_common_pkg::get_signal_width($clog2(DATA_SIZE), true); + + var offset: logic ; + var size : PKG::pzcorebus_mlength_unpacked[2]; + + offset = sresp_offset as OFFSET_WIDTH; + size[0] = (DATA_SIZE as PKG::pzcorebus_mlength_unpacked) - (offset as PKG::pzcorebus_mlength_unpacked); + size[1] = mlength - sresp_count; + + if size[0] <: size[1] { + return size[0]; + } else { + return size[1]; + } + } + + function get_sresp_uniten( + sresp_offset: input PKG::pzcorebus_sresp_offset, + sresp_size : input PKG::pzcorebus_sresp_size , + ) -> PKG::pzcorebus_sresp_uniten { + var start_index: PKG::pzcorebus_sresp_offset; + var end_index : PKG::pzcorebus_sresp_offset; + var uniten : PKG::pzcorebus_sresp_uniten; + + start_index = sresp_offset; + end_index = start_index + (sresp_size as PKG::pzcorebus_sresp_offset); + for i in 0..$bits(PKG::pzcorebus_sresp_uniten) { + let index: PKG::pzcorebus_sresp_offset = i as PKG::pzcorebus_sresp_offset; + uniten[i] = (index >= start_index) && (index <: end_index); + } + + return uniten; + } +} diff --git a/veryl/pzcorebus_fifo/pzcorebus_fifo.veryl b/veryl/pzcorebus_fifo/pzcorebus_fifo.veryl new file mode 100644 index 0000000..8a11a4b --- /dev/null +++ b/veryl/pzcorebus_fifo/pzcorebus_fifo.veryl @@ -0,0 +1,217 @@ +//======================================== +// +// Copyright (c) 2025 PEZY Computing, K.K. +// +//======================================== +pub module pzcorebus_fifo::#( + param MCMD_DEPTH : u32 = 2 , + param MCMD_THRESHOLD : u32 = MCMD_DEPTH , + param MCMD_VALID : bbool = true , + param MDATA_DEPTH : u32 = 2 , + param MDATA_THRESHOLD: u32 = MDATA_DEPTH, + param MDATA_VALID : bbool = true , + param SRESP_DEPTH : u32 = 2 , + param SRESP_THRESHOLD: u32 = SRESP_DEPTH, + param SRESP_VALID : bbool = true , + param FLAG_FF_OUT : bbool = true , + param DATA_FF_OUT : bbool = true , + param RESET_DATA_FF : bbool = true , +)( + i_clk : input clock , + i_rst : input reset , + i_clear : input logic = false, + o_empty : output logic<3> = _ , + o_almost_full: output logic<3> = _ , + o_full : output logic<3> = _ , + slave_if : modport pzcorebus_if::::slave , + master_if : modport pzcorebus_if::::master , +) { + const BUS_CONFIG: pzcorebus_common_pkg::pzcorebus_config = PKG::BUS_CONFIG; + + var scmd_accept : logic<2> ; + var mcmd_valid : logic<2> ; + var mcmd : PKG::pzcorebus_packed_mcmd<2> ; + var sdata_accept: logic<2> ; + var mdata_valid : logic<2> ; + var mdata : PKG::pzcorebus_packed_mdata<2>; + var mresp_accept: logic<2> ; + var sresp_valid : logic<2> ; + var sresp : PKG::pzcorebus_packed_sresp<2>; + + always_comb { + slave_if.scmd_accept = scmd_accept[0]; + slave_if.sdata_accept = sdata_accept[0]; + mcmd_valid[0] = slave_if.mcmd_valid; + mdata_valid[0] = slave_if.mdata_valid; + mcmd[0] = slave_if.get_packed_mcmd(); + mdata[0] = slave_if.get_packed_mdata(); + } + + always_comb { + scmd_accept[1] = master_if.scmd_accept; + sdata_accept[1] = master_if.sdata_accept; + master_if.mcmd_valid = mcmd_valid[1]; + master_if.mdata_valid = mdata_valid[1]; + master_if.put_packed_mcmd(mcmd[1]); + master_if.put_packed_mdata(mdata[1]); + } + + always_comb { + mresp_accept[0] = slave_if.mresp_accept; + slave_if.sresp_valid = sresp_valid[0]; + slave_if.put_packed_sresp(sresp[0]); + } + + always_comb { + master_if.mresp_accept = mresp_accept[1]; + sresp_valid[1] = master_if.sresp_valid; + sresp[1] = master_if.get_packed_sresp(); + } + + if MCMD_VALID && MCMD_DEPTH >= 1 :g_mcmd { + var status: logic<3>; + + always_comb { + o_empty[0] = status[0]; + o_almost_full[0] = status[1]; + o_full[0] = status[2]; + } + + always_comb { + scmd_accept[0] = !status[2]; + mcmd_valid[1] = !status[0]; + } + + inst u_fifo: $std::fifo #( + TYPE : PKG::pzcorebus_packed_mcmd, + DEPTH : MCMD_DEPTH , + THRESHOLD : MCMD_THRESHOLD , + FLAG_FF_OUT : FLAG_FF_OUT , + DATA_FF_OUT : DATA_FF_OUT , + RESET_DATA_FF: RESET_DATA_FF , + )( + i_clk : i_clk , + i_rst : i_rst , + i_clear : i_clear , + o_empty : status[0] , + o_almost_full: status[1] , + o_full : status[2] , + o_word_count : _ , + i_push : mcmd_valid[0] , + i_data : mcmd[0] , + i_pop : scmd_accept[1], + o_data : mcmd[1] , + ); + } else { + always_comb { + o_empty[0] = '1; + o_almost_full[0] = '0; + o_full[0] = '0; + } + + always_comb { + scmd_accept[0] = scmd_accept[1]; + mcmd_valid[1] = mcmd_valid[0]; + mcmd[1] = mcmd[0]; + } + } + + if MDATA_VALID + && MDATA_DEPTH >= 1 + && BUS_CONFIG.profile != PKG::pzcorebus_profile::CSR :g_mdata + { + var status: logic<3>; + + always_comb { + o_empty[1] = status[0]; + o_almost_full[1] = status[1]; + o_full[1] = status[2]; + } + + always_comb { + sdata_accept[0] = !status[2]; + mdata_valid[1] = !status[0]; + } + + inst u_fifo: $std::fifo #( + TYPE : PKG::pzcorebus_packed_mdata, + DEPTH : MDATA_DEPTH , + THRESHOLD : MDATA_THRESHOLD , + FLAG_FF_OUT : FLAG_FF_OUT , + DATA_FF_OUT : DATA_FF_OUT , + RESET_DATA_FF: RESET_DATA_FF , + )( + i_clk : i_clk , + i_rst : i_rst , + i_clear : i_clear , + o_empty : status[0] , + o_almost_full: status[1] , + o_full : status[2] , + o_word_count : _ , + i_push : mdata_valid[0] , + i_data : mdata[0] , + i_pop : sdata_accept[1], + o_data : mdata[1] , + ); + } else { + always_comb { + o_empty[1] = '1; + o_almost_full[1] = '0; + o_full[1] = '0; + } + + always_comb { + sdata_accept[0] = sdata_accept[1]; + mdata_valid[1] = mdata_valid[0]; + mdata[1] = mdata[0]; + } + } + + if SRESP_VALID && SRESP_DEPTH >= 1 :g_sresp { + var status: logic<3>; + + always_comb { + o_empty[2] = status[0]; + o_almost_full[2] = status[1]; + o_full[2] = status[2]; + } + + always_comb { + mresp_accept[1] = !status[2]; + sresp_valid[0] = !status[0]; + } + + inst u_fifo: $std::fifo #( + TYPE : PKG::pzcorebus_packed_sresp, + DEPTH : SRESP_DEPTH , + THRESHOLD : SRESP_THRESHOLD , + FLAG_FF_OUT : FLAG_FF_OUT , + DATA_FF_OUT : DATA_FF_OUT , + RESET_DATA_FF: RESET_DATA_FF , + )( + i_clk : i_clk , + i_rst : i_rst , + i_clear : i_clear , + o_empty : status[0] , + o_almost_full: status[1] , + o_full : status[2] , + o_word_count : _ , + i_push : sresp_valid[1] , + i_data : sresp[1] , + i_pop : mresp_accept[0], + o_data : sresp[0] , + ); + } else { + always_comb { + o_empty[2] = '1; + o_almost_full[2] = '0; + o_full[2] = '0; + } + + always_comb { + mresp_accept[1] = mresp_accept[0]; + sresp_valid[0] = sresp_valid[1]; + sresp[0] = sresp[1]; + } + } +} diff --git a/veryl/pzcorebus_fifo/pzcorebus_mcmd_fifo.veryl b/veryl/pzcorebus_fifo/pzcorebus_mcmd_fifo.veryl new file mode 100644 index 0000000..1e8ca70 --- /dev/null +++ b/veryl/pzcorebus_fifo/pzcorebus_mcmd_fifo.veryl @@ -0,0 +1,86 @@ +//======================================== +// +// Copyright (c) 2025 PEZY Computing, K.K. +// +//======================================== +pub module pzcorebus_mcmd_fifo::#( + param MCMD_DEPTH : u32 = 2 , + param MCMD_THRESHOLD : u32 = MCMD_DEPTH , + param MCMD_VALID : bbool = true , + param FLAG_FF_OUT : bbool = true , + param DATA_FF_OUT : bbool = true , + param RESET_DATA_FF : bbool = true , +)( + i_clk : input clock , + i_rst : input reset , + i_clear : input logic = false, + o_empty : output logic = _ , + o_almost_full: output logic = _ , + o_full : output logic = _ , + slave_if : modport pzcorebus_if::::slave_mcmd , + master_if : modport pzcorebus_if::::master_mcmd , +) { + var scmd_accept: logic<2>; + var mcmd_valid : logic<2>; + var mcmd : PKG::pzcorebus_packed_mcmd<2>; + + always_comb { + slave_if.scmd_accept = scmd_accept[0]; + mcmd_valid[0] = slave_if.mcmd_valid; + mcmd[0] = slave_if.get_packed_mcmd(); + } + + always_comb { + scmd_accept[1] = master_if.scmd_accept; + master_if.mcmd_valid = mcmd_valid[1]; + master_if.put_packed_mcmd(mcmd[1]); + } + + if MCMD_VALID && MCMD_DEPTH >= 1 :g { + var status: logic<3>; + + always_comb { + o_empty = status[0]; + o_almost_full = status[1]; + o_full = status[2]; + } + + always_comb { + scmd_accept[0] = !status[2]; + mcmd_valid[1] = !status[0]; + } + + inst u_fifo: $std::fifo #( + TYPE : PKG::pzcorebus_packed_mcmd, + DEPTH : MCMD_DEPTH , + THRESHOLD : MCMD_THRESHOLD , + FLAG_FF_OUT : FLAG_FF_OUT , + DATA_FF_OUT : DATA_FF_OUT , + RESET_DATA_FF: RESET_DATA_FF , + )( + i_clk : i_clk , + i_rst : i_rst , + i_clear : i_clear , + o_empty : status[0] , + o_almost_full: status[1] , + o_full : status[2] , + o_word_count : _ , + i_push : mcmd_valid[0] , + i_data : mcmd[0] , + i_pop : scmd_accept[1], + o_data : mcmd[1] , + ); + } else { + always_comb { + o_empty = '1; + o_almost_full = '0; + o_full = '0; + } + + always_comb { + scmd_accept[0] = scmd_accept[1]; + mcmd_valid[1] = mcmd_valid[0]; + mcmd[1] = mcmd[0]; + } + } +} diff --git a/veryl/pzcorebus_fifo/pzcorebus_mreq_fifo.veryl b/veryl/pzcorebus_fifo/pzcorebus_mreq_fifo.veryl new file mode 100644 index 0000000..aba75b3 --- /dev/null +++ b/veryl/pzcorebus_fifo/pzcorebus_mreq_fifo.veryl @@ -0,0 +1,151 @@ +//======================================== +// +// Copyright (c) 2026 PEZY Computing, K.K. +// +//======================================== +pub module pzcorebus_mreq_fifo:: #( + param MCMD_DEPTH : u32 = 2 , + param MCMD_THRESHOLD : u32 = MCMD_DEPTH , + param MCMD_VALID : bbool = true , + param MDATA_DEPTH : u32 = 2 , + param MDATA_THRESHOLD: u32 = MDATA_DEPTH, + param MDATA_VALID : bbool = true , + param FLAG_FF_OUT : bbool = true , + param DATA_FF_OUT : bbool = true , + param RESET_DATA_FF : bbool = true , +)( + i_clk : input clock , + i_rst : input reset , + i_clear : input logic = false, + o_empty : output logic<2> = _ , + o_almost_full: output logic<2> = _ , + o_full : output logic<2> = _ , + slave_if : modport pzcorebus_if::::slave_mreq , + master_if : modport pzcorebus_if::::master_mreq , +) { + import pzcorebus_common_pkg::is_mem_profile; + + var scmd_accept : logic<2> ; + var mcmd_valid : logic<2> ; + var mcmd : PKG::pzcorebus_packed_mcmd<2> ; + var sdata_accept: logic<2> ; + var mdata_valid : logic<2> ; + var mdata : PKG::pzcorebus_packed_mdata<2>; + + always_comb { + slave_if.scmd_accept = scmd_accept[0]; + slave_if.sdata_accept = sdata_accept[0]; + mcmd_valid[0] = slave_if.mcmd_valid; + mdata_valid[0] = slave_if.mdata_valid; + mcmd[0] = slave_if.get_packed_mcmd(); + mdata[0] = slave_if.get_packed_mdata(); + } + + always_comb { + scmd_accept[1] = master_if.scmd_accept; + sdata_accept[1] = master_if.sdata_accept; + master_if.mcmd_valid = mcmd_valid[1]; + master_if.mdata_valid = mdata_valid[1]; + master_if.put_packed_mcmd(mcmd[1]); + master_if.put_packed_mdata(mdata[1]); + } + + if MCMD_VALID && MCMD_DEPTH >= 1 :g_mcmd { + var status: logic<3>; + + always_comb { + o_empty[0] = status[0]; + o_almost_full[0] = status[1]; + o_full[0] = status[2]; + } + + always_comb { + scmd_accept[0] = !status[2]; + mcmd_valid[1] = !status[0]; + } + + inst u_fifo: $std::fifo #( + TYPE : PKG::pzcorebus_packed_mcmd, + DEPTH : MCMD_DEPTH , + THRESHOLD : MCMD_THRESHOLD , + FLAG_FF_OUT : FLAG_FF_OUT , + DATA_FF_OUT : DATA_FF_OUT , + RESET_DATA_FF: RESET_DATA_FF , + )( + i_clk : i_clk , + i_rst : i_rst , + i_clear : i_clear , + o_empty : status[0] , + o_almost_full: status[1] , + o_full : status[2] , + o_word_count : _ , + i_push : mcmd_valid[0] , + i_data : mcmd[0] , + i_pop : scmd_accept[1], + o_data : mcmd[1] , + ); + } else { + always_comb { + o_empty[0] = '1; + o_almost_full[0] = '0; + o_full[0] = '0; + } + + always_comb { + scmd_accept[0] = scmd_accept[1]; + mcmd_valid[1] = mcmd_valid[0]; + mcmd[1] = mcmd[0]; + } + } + + if MDATA_VALID + && MDATA_DEPTH >= 1 + && is_mem_profile(PKG::BUS_CONFIG) :g_mdata + { + var status: logic<3>; + + always_comb { + o_empty[1] = status[0]; + o_almost_full[1] = status[1]; + o_full[1] = status[2]; + } + + always_comb { + sdata_accept[0] = !status[2]; + mdata_valid[1] = !status[0]; + } + + inst u_fifo: $std::fifo #( + TYPE : PKG::pzcorebus_packed_mdata, + DEPTH : MDATA_DEPTH , + THRESHOLD : MDATA_THRESHOLD , + FLAG_FF_OUT : FLAG_FF_OUT , + DATA_FF_OUT : DATA_FF_OUT , + RESET_DATA_FF: RESET_DATA_FF , + )( + i_clk : i_clk , + i_rst : i_rst , + i_clear : i_clear , + o_empty : status[0] , + o_almost_full: status[1] , + o_full : status[2] , + o_word_count : _ , + i_push : mdata_valid[0] , + i_data : mdata[0] , + i_pop : sdata_accept[1], + o_data : mdata[1] , + ); + } else { + always_comb { + o_empty[1] = '1; + o_almost_full[1] = '0; + o_full[1] = '0; + } + + always_comb { + sdata_accept[0] = sdata_accept[1]; + mdata_valid[1] = mdata_valid[0]; + mdata[1] = mdata[0]; + } + } +} diff --git a/veryl/pzcorebus_fifo/pzcorebus_sresp_fifo.veryl b/veryl/pzcorebus_fifo/pzcorebus_sresp_fifo.veryl new file mode 100644 index 0000000..145adc4 --- /dev/null +++ b/veryl/pzcorebus_fifo/pzcorebus_sresp_fifo.veryl @@ -0,0 +1,86 @@ +//======================================== +// +// Copyright (c) 2026 PEZY Computing, K.K. +// +//======================================== +pub module pzcorebus_sresp_fifo:: #( + param SRESP_DEPTH : u32 = 2 , + param SRESP_THRESHOLD: u32 = SRESP_DEPTH, + param SRESP_VALID : bbool = true , + param FLAG_FF_OUT : bbool = true , + param DATA_FF_OUT : bbool = true , + param RESET_DATA_FF : bbool = true , +)( + i_clk : input clock , + i_rst : input reset , + i_clear : input logic = false , + o_empty : output logic = _ , + o_almost_full: output logic = _ , + o_full : output logic = _ , + slave_if : modport pzcorebus_if::::slave_sresp , + master_if : modport pzcorebus_if::::master_sresp, +) { + var mresp_accept: logic<2> ; + var sresp_valid : logic<2> ; + var sresp : PKG::pzcorebus_packed_sresp<2>; + + always_comb { + mresp_accept[0] = slave_if.mresp_accept; + slave_if.sresp_valid = sresp_valid[0]; + slave_if.put_packed_sresp(sresp[0]); + } + + always_comb { + master_if.mresp_accept = mresp_accept[1]; + sresp_valid[1] = master_if.sresp_valid; + sresp[1] = master_if.get_packed_sresp(); + } + + if SRESP_VALID && SRESP_DEPTH >= 1 :g_sresp { + var status: logic<3>; + + always_comb { + o_empty = status[0]; + o_almost_full = status[1]; + o_full = status[2]; + } + + always_comb { + sresp_valid[0] = !status[0]; + mresp_accept[1] = !status[2]; + } + + inst u_fifo: $std::fifo #( + TYPE : PKG::pzcorebus_packed_sresp, + DEPTH : SRESP_DEPTH , + THRESHOLD : SRESP_THRESHOLD , + FLAG_FF_OUT : FLAG_FF_OUT , + DATA_FF_OUT : DATA_FF_OUT , + RESET_DATA_FF: RESET_DATA_FF , + )( + i_clk : i_clk , + i_rst : i_rst , + i_clear : i_clear , + o_empty : status[0] , + o_almost_full: status[1] , + o_full : status[2] , + o_word_count : _ , + i_push : sresp_valid[1] , + i_data : sresp[1] , + i_pop : mresp_accept[0], + o_data : sresp[0] , + ); + } else { + always_comb { + o_empty = true; + o_almost_full = false; + o_full = false; + } + + always_comb { + mresp_accept[1] = mresp_accept[0]; + sresp_valid[0] = sresp_valid[1]; + sresp[0] = sresp[1]; + } + } +} diff --git a/veryl/pzcorebus_mreq_aligner/pzcorebus_mreq_aligner.veryl b/veryl/pzcorebus_mreq_aligner/pzcorebus_mreq_aligner.veryl new file mode 100644 index 0000000..bba26f2 --- /dev/null +++ b/veryl/pzcorebus_mreq_aligner/pzcorebus_mreq_aligner.veryl @@ -0,0 +1,57 @@ +//======================================== +// +// Copyright (c) 2026 PEZY Computing, K.K. +// +//======================================== +pub module pzcorebus_mreq_aligner:: #( + param WAIT_FOR_DATA : bbool = false, + param THROUGH_NO_DATA_COMMAND: bbool = false, + param SLAVE_FIFO : bbool = false, + param SLAVE_FIFO_MCMD_DEPTH : u32 = 2 , + param SLAVE_FIFO_MDATA_DEPTH : u32 = 2 , + param SLAVE_FIFO_SRESP_DEPTH : u32 = 2 , +)( + i_clk : input clock , + i_rst : input reset , + o_mcmd : output PKG::pzcorebus_bundled_mcmd = _, + o_mcmd_done : output logic = _, + o_mdata_done: output logic = _, + slave_if : modport pzcorebus_if::::slave , + master_if : modport pzcorebus_if::::master , +) { + inst bus_if: pzcorebus_if::[2]; + + always_comb { + slave_if <> bus_if[0].master; + } + + inst u_core: pzcorebus_mreq_aligner_core:: #( + WAIT_FOR_DATA : WAIT_FOR_DATA , + THROUGH_NO_DATA_COMMAND: THROUGH_NO_DATA_COMMAND, + SLAVE_FIFO : SLAVE_FIFO , + SLAVE_FIFO_MCMD_DEPTH : SLAVE_FIFO_MCMD_DEPTH , + SLAVE_FIFO_MDATA_DEPTH : SLAVE_FIFO_MDATA_DEPTH , + )( + i_clk : i_clk , + i_rst : i_rst , + o_mcmd : o_mcmd , + o_mcmd_done : o_mcmd_done , + o_mdata_done: o_mdata_done, + slave_if : bus_if[0] , + master_if : bus_if[1] , + ); + + inst u_sresp_fifo: pzcorebus_sresp_fifo:: #( + SRESP_VALID: SLAVE_FIFO , + SRESP_DEPTH: SLAVE_FIFO_SRESP_DEPTH, + )( + i_clk : i_clk , + i_rst : i_rst , + slave_if : bus_if[0], + master_if: bus_if[1], + ); + + always_comb { + bus_if[1].slave <> master_if; + } +} diff --git a/veryl/pzcorebus_mreq_aligner/pzcorebus_mreq_aligner_core.veryl b/veryl/pzcorebus_mreq_aligner/pzcorebus_mreq_aligner_core.veryl new file mode 100644 index 0000000..bfe1192 --- /dev/null +++ b/veryl/pzcorebus_mreq_aligner/pzcorebus_mreq_aligner_core.veryl @@ -0,0 +1,186 @@ +//======================================== +// +// Copyright (c) 2026 PEZY Computing, K.K. +// +//======================================== +pub module pzcorebus_mreq_aligner_core:: #( + param WAIT_FOR_DATA : bbool = false, + param THROUGH_NO_DATA_COMMAND: bbool = false, + param SLAVE_FIFO : bbool = false, + param SLAVE_FIFO_MCMD_DEPTH : u32 = 2 , + param SLAVE_FIFO_MDATA_DEPTH : u32 = 2 , +)( + i_clk : input clock , + i_rst : input reset , + o_mcmd : output PKG::pzcorebus_bundled_mcmd = _, + o_mcmd_done : output logic = _, + o_mdata_done: output logic = _, + slave_if : modport pzcorebus_if::::slave_mreq , + master_if : modport pzcorebus_if::::master_mreq , +) { +//-------------------------------------------------------------- +// Slave IF FIFO +//-------------------------------------------------------------- + inst fifo_if: pzcorebus_if::; + + inst u_slave_fifo: pzcorebus_mreq_fifo:: #( + MCMD_VALID : SLAVE_FIFO , + MCMD_DEPTH : SLAVE_FIFO_MCMD_DEPTH , + MDATA_VALID: SLAVE_FIFO , + MDATA_DEPTH: SLAVE_FIFO_MDATA_DEPTH, + )( + i_clk : i_clk , + i_rst : i_rst , + slave_if : slave_if, + master_if: fifo_if , + ); + +//-------------------------------------------------------------- +// State Machine +//-------------------------------------------------------------- + enum state { + IDLE , + ACTIVE, + DONE , + } + + var mcmd_state : state; + var mcmd_done : logic; + var mdata_state: state; + var mdata_done : logic; + + always_comb { + o_mcmd_done = mcmd_state == state::DONE; + o_mdata_done = mdata_state == state::DONE; + } + + always_comb { + mcmd_done = (mcmd_state == state::DONE) || fifo_if.mcmd_with_data_ack(); + mdata_done = (mdata_state == state::DONE) || fifo_if.mdata_last_ack(); + } + + always_ff { + if_reset { + mcmd_state = state::IDLE; + } else { + case mcmd_state { + state::IDLE: { + if mcmd_done && !mdata_done { + mcmd_state = state::DONE; + } + } + state::DONE: { + if mdata_done { + mcmd_state = state::IDLE; + } + } + } + } + } + + always_ff { + if_reset { + mdata_state = state::IDLE; + } else { + case mdata_state { + state::IDLE: { + if mcmd_done { + if !mdata_done { + mdata_state = state::ACTIVE; + } + } else if fifo_if.mcmd_with_data_valid() { + if mdata_done { + mdata_state = state::DONE; + } else if !WAIT_FOR_DATA || fifo_if.mdata_valid { + mdata_state = state::ACTIVE; + } + } + } + state::ACTIVE: { + if mdata_done { + if mcmd_done { + mdata_state = state::IDLE; + } else { + mdata_state = state::DONE; + } + } + } + state::DONE: { + if mcmd_done { + mdata_state = state::IDLE; + } + } + } + } + } + +//-------------------------------------------------------------- +// Aligner +//-------------------------------------------------------------- + var mcmd_active : logic; + var mdata_active: logic; + + always_comb { + case mcmd_state { + state::IDLE: { + mcmd_active = + !WAIT_FOR_DATA || fifo_if.is_mcmd_no_data() || fifo_if.mdata_valid || mdata_done; + } + default: { + mcmd_active = + THROUGH_NO_DATA_COMMAND && fifo_if.is_mcmd_no_data(); + } + } + + case mdata_state { + state::IDLE: { + mdata_active = fifo_if.mcmd_with_data_valid(); + } + state::ACTIVE: { + mdata_active = true; + } + default: { + mdata_active = false; + } + } + + master_if.put_mcmd(fifo_if.get_mcmd()); + if mcmd_active { + fifo_if.scmd_accept = master_if.scmd_accept; + master_if.mcmd_valid = fifo_if.mcmd_valid; + } else { + fifo_if.scmd_accept = false; + master_if.mcmd_valid = false; + } + + master_if.put_mdata(fifo_if.get_mdata()); + if mdata_active { + fifo_if.sdata_accept = master_if.sdata_accept; + master_if.mdata_valid = fifo_if.mdata_valid; + } else { + fifo_if.sdata_accept = false; + master_if.mdata_valid = false; + } + } + +//-------------------------------------------------------------- +// Request Info +//-------------------------------------------------------------- + var mcmd: PKG::pzcorebus_bundled_mcmd; + + always_comb { + if mcmd_state == state::IDLE { + o_mcmd = fifo_if.get_mcmd(); + } else { + o_mcmd = mcmd; + } + } + + always_ff { + if_reset { + mcmd = 0 as PKG::pzcorebus_bundled_mcmd; + } else if fifo_if.mcmd_with_data_ack() { + mcmd = fifo_if.get_mcmd(); + } + } +} diff --git a/veryl/pzcorebus_mreq_packer/pzcorebus_mreq_mdata_fifo.veryl b/veryl/pzcorebus_mreq_packer/pzcorebus_mreq_mdata_fifo.veryl new file mode 100644 index 0000000..0d4946c --- /dev/null +++ b/veryl/pzcorebus_mreq_packer/pzcorebus_mreq_mdata_fifo.veryl @@ -0,0 +1,55 @@ +//======================================== +// +// Copyright (c) 2025 PEZY Computing, K.K. +// +//======================================== +module pzcorebus_mreq_packer_mdata_fifo::< + BUS_PKG : pzcorebus_proto_pkg , + SRAM_PKG: pzbcm_sram_proto_pkg, +> ( + i_clk : input clock , + i_rst : input reset , + i_clear : input logic , + o_empty : output logic , + o_full : output logic , + i_sram_config: input SRAM_PKG::SRAM_CONFIG_TYPE , + slave_if : modport pzcorebus_if::::slave_mdata , + master_if : modport pzcorebus_if::::master_mdata, +) { + var empty : logic ; + var full : logic ; + var push : logic ; + var push_data: BUS_PKG::pzcorebus_packed_mdata; + var pop : logic ; + var pop_data : BUS_PKG::pzcorebus_packed_mdata; + + always_comb { + slave_if.sdata_accept = !full; + push = slave_if.mdata_valid; + push_data = slave_if.get_packed_mdata(); + } + + always_comb { + pop = master_if.sdata_accept; + master_if.mdata_valid = !empty; + master_if.put_packed_mdata(pop_data); + } + + inst u_fifo: pzbcm_sram_fifo:: #( + TYPE: BUS_PKG::pzcorebus_packed_mdata, + )( + i_clk : i_clk , + i_rst : i_rst , + i_clear : i_clear , + i_sram_config : i_sram_config, + o_empty : empty , + o_completely_empty: o_empty , + o_almost_full : _ , + o_full : full , + o_completely_full : o_full , + i_push : push , + i_data : push_data , + i_pop : pop , + o_data : pop_data , + ); +} diff --git a/veryl/pzcorebus_mreq_packer/pzcorebus_mreq_packer.veryl b/veryl/pzcorebus_mreq_packer/pzcorebus_mreq_packer.veryl new file mode 100644 index 0000000..a740077 --- /dev/null +++ b/veryl/pzcorebus_mreq_packer/pzcorebus_mreq_packer.veryl @@ -0,0 +1,173 @@ +//======================================== +// +// Copyright (c) 2025 PEZY Computing, K.K. +// +//======================================== +pub module pzcorebus_mreq_packer::< + BUS_PKG : pzcorebus_proto_pkg , + SRAM_PKG: pzbcm_sram_proto_pkg, +> #( + param MCMD_DEPTH : u16 = 2 , + param SLAVE_SLICER : bit<2> = '0, + param MASTER_SLICER: bit<2> = '0, +)( + i_clk : input clock , + i_rst : input reset , + i_clear : input logic , + o_empty : output logic<2> , + o_full : output logic<2> , + i_sram_config: input SRAM_PKG::SRAM_CONFIG_TYPE , + slave_if : modport pzcorebus_if::::slave , + master_if : modport pzcorebus_if::::master, +) { + inst bus_if: pzcorebus_if::[3]; + +//-------------------------------------------------------------- +// Slave slicer +//-------------------------------------------------------------- + inst u_slave_slicer: pzcorebus_slicer:: #( + MCMD_VALID : SLAVE_SLICER[0], + MDATA_VALID: SLAVE_SLICER[0], + SRESP_VALID: SLAVE_SLICER[1], + )( + i_clk : i_clk , + i_rst : i_rst , + slave_if : slave_if , + master_if: bus_if[0], + ); + +//-------------------------------------------------------------- +// Command FIFO +//-------------------------------------------------------------- + inst u_mcmd_fifo: pzcorebus_mcmd_fifo:: #( + MCMD_DEPTH: MCMD_DEPTH, + )( + i_clk : i_clk , + i_rst : i_rst , + i_clear : i_clear , + o_empty : o_empty[0] , + o_almost_full: _ , + o_full : o_full[0] , + slave_if : bus_if[0] , + master_if : bus_if[1] , + ); + +//-------------------------------------------------------------- +// Data FIFO +//-------------------------------------------------------------- + inst u_mdata_fifo: pzcorebus_mreq_packer_mdata_fifo:: ( + i_clk : i_clk , + i_rst : i_rst , + i_clear : i_clear , + o_empty : o_empty[1] , + o_full : o_full[1] , + i_sram_config: i_sram_config, + slave_if : bus_if[0] , + master_if : bus_if[1] , + ); + +//-------------------------------------------------------------- +// Request control +//-------------------------------------------------------------- + const WRITE_REQ_COUNT_WIDTH: u16 = $clog2(MCMD_DEPTH + 1); + + var write_req_count_up : logic; + var write_req_count_down: logic; + var write_req_count : logic; + var write_ready : logic; + var write_done : logic; + var write_command_ack : logic; + var write_command_done : logic; + var write_data_ack : logic; + var write_data_done : logic; + + always_comb { + write_req_count_up = bus_if[0].mdata_last_ack(); + write_req_count_down = write_done; + } + + always_ff { + if_reset { + write_req_count = 0 as WRITE_REQ_COUNT_WIDTH; + } else if i_clear { + write_req_count = 0 as WRITE_REQ_COUNT_WIDTH; + } else { + case {write_req_count_up, write_req_count_down} { + 2'b10: write_req_count += 1 as WRITE_REQ_COUNT_WIDTH; + 2'b01: write_req_count -= 1 as WRITE_REQ_COUNT_WIDTH; + } + } + } + + always_comb { + write_command_ack = bus_if[1].mcmd_with_data_ack(); + write_data_ack = bus_if[1].mdata_last_ack(); + write_done = + (write_command_ack && write_data_ack ) || + (write_command_ack && write_data_done) || + (write_command_done && write_data_ack ); + } + + always_ff { + if_reset { + write_command_done = false; + write_data_done = false; + } else if i_clear || write_done { + write_command_done = false; + write_data_done = false; + } else { + if write_command_ack { + write_command_done = true; + } + if write_data_ack { + write_data_done = true; + } + } + } + + always_comb { + write_ready = + (write_command_done || bus_if[1].mcmd_with_data_valid()) + && (write_req_count != (0 as WRITE_REQ_COUNT_WIDTH)); + + if write_ready { + bus_if[1].scmd_accept = (!write_command_done) && bus_if[2].scmd_accept; + bus_if[2].mcmd_valid = (!write_command_done) && bus_if[1].mcmd_valid; + bus_if[1].sdata_accept = (!write_data_done ) && bus_if[2].sdata_accept; + bus_if[2].mdata_valid = (!write_data_done ) && bus_if[1].mdata_valid; + } else if bus_if[1].is_mcmd_no_data() { + bus_if[1].scmd_accept = bus_if[2].scmd_accept; + bus_if[2].mcmd_valid = bus_if[1].mcmd_valid; + bus_if[1].sdata_accept = '0; + bus_if[2].mdata_valid = '0; + } else { + bus_if[1].scmd_accept = '0; + bus_if[2].mcmd_valid = '0; + bus_if[1].sdata_accept = '0; + bus_if[2].mdata_valid = '0; + } + + bus_if[2].put_mcmd(bus_if[1].get_mcmd()); + bus_if[2].put_mdata(bus_if[1].get_mdata()); + } + +//-------------------------------------------------------------- +// Through response +//-------------------------------------------------------------- + connect bus_if[0].slave_sresp <> bus_if[1].master_sresp; + connect bus_if[1].slave_sresp <> bus_if[2].master_sresp; + +//-------------------------------------------------------------- +// Master slicer +//-------------------------------------------------------------- + inst u_master_slicer: pzcorebus_slicer:: #( + MCMD_VALID : MASTER_SLICER[0], + MDATA_VALID: MASTER_SLICER[0], + SRESP_VALID: MASTER_SLICER[1], + )( + i_clk : i_clk , + i_rst : i_rst , + slave_if : bus_if[2], + master_if: master_if, + ); +} diff --git a/veryl/pzcorebus_selector/pzcorebus_mreq_mux.veryl b/veryl/pzcorebus_selector/pzcorebus_mreq_mux.veryl new file mode 100644 index 0000000..cc5fe2c --- /dev/null +++ b/veryl/pzcorebus_selector/pzcorebus_mreq_mux.veryl @@ -0,0 +1,79 @@ +//======================================== +// +// Copyright (c) 2026 PEZY Computing, K.K. +// +//======================================== +pub module pzcorebus_mreq_mux:: #( + param SLAVES : u32 = 2 , + param KIND : selector_kind = selector_kind::ONEHOT , + param SELECT_WIDTH: u32 = calc_select_width(SLAVES, KIND), +)( + i_mcmd_select : input logic , + i_mdata_select: input logic , + slave_if : modport pzcorebus_if::::slave_mreq[SLAVES], + master_if : modport pzcorebus_if::::master_mreq , +){ + import $std::selector_pkg::*; + import pzcorebus_common_pkg::is_mem_profile; + + var s_scmd_accept : logic ; + var s_mcmd_valid : logic ; + var s_mcmd : PKG::pzcorebus_packed_mcmd ; + var s_sdata_accept: logic ; + var s_mdata_valid : logic ; + var s_mdata : PKG::pzcorebus_packed_mdata; + var m_sdmc_accept : logic ; + var m_mcmd_valid : logic ; + var m_mcmd : PKG::pzcorebus_packed_mcmd ; + var m_sdata_accept: logic ; + var m_mdata_valid : logic ; + var m_mdata : PKG::pzcorebus_packed_mdata ; + + for i in 0..SLAVES :g_slave { + always_comb { + slave_if[i].scmd_accept = s_scmd_accept[i]; + s_mcmd_valid[i] = slave_if[i].mcmd_valid; + s_mcmd[i] = slave_if[i].get_packed_mcmd(); + + slave_if[i].sdata_accept = s_sdata_accept[i]; + s_mdata_valid[i] = slave_if[i].mdata_valid; + s_mdata[i] = slave_if[i].get_packed_mdata(); + } + } + + always_comb { + s_scmd_accept = $std::dispatch::(i_mcmd_select, m_sdmc_accept, false); + } + + always_comb { + m_mcmd_valid = $std::select::(i_mcmd_select, s_mcmd_valid); + m_mcmd = $std::select::(i_mcmd_select, s_mcmd); + } + + if is_mem_profile(PKG::BUS_CONFIG) :g_mdata { + always_comb { + s_sdata_accept = $std::dispatch::(i_mdata_select, m_sdata_accept, false); + } + + always_comb { + m_mdata_valid = $std::select::(i_mdata_select, s_mdata_valid); + m_mdata = $std::select::(i_mdata_select, s_mdata); + } + } else { + always_comb { + s_sdata_accept = '0; + m_mdata_valid = '0; + m_mdata = '0; + } + } + + always_comb { + m_sdmc_accept = master_if.scmd_accept; + master_if.mcmd_valid = m_mcmd_valid; + master_if.put_packed_mcmd(m_mcmd); + + m_sdata_accept = master_if.sdata_accept; + master_if.mdata_valid = m_mdata_valid; + master_if.put_packed_mdata(m_mdata); + } +} diff --git a/veryl/pzcorebus_selector/pzcorebus_sresp_demux.veryl b/veryl/pzcorebus_selector/pzcorebus_sresp_demux.veryl new file mode 100644 index 0000000..1a6edab --- /dev/null +++ b/veryl/pzcorebus_selector/pzcorebus_sresp_demux.veryl @@ -0,0 +1,41 @@ +pub module pzcorebus_sresp_demux:: #( + param MASTERS : u32 = 2 , + param KIND : selector_kind = selector_kind::ONEHOT , + param SELECT_WIDTH: u32 = calc_select_width(MASTERS, KIND), +)( + i_sresp_select: input logic , + slave_if : modport pzcorebus_if::::slave_sresp , + master_if : modport pzcorebus_if::::master_sresp[MASTERS], +) { + import $std::selector_pkg::*; + + var s_mresp_accept: logic ; + var s_sresp_valid : logic ; + var s_sresp : PKG::pzcorebus_packed_sresp ; + var m_mresp_accept: logic ; + var m_sresp_valid : logic ; + var m_sresp : PKG::pzcorebus_packed_sresp; + + always_comb { + s_mresp_accept = slave_if.mresp_accept; + slave_if.sresp_valid = s_sresp_valid; + slave_if.put_packed_sresp(s_sresp); + } + + always_comb { + m_mresp_accept = $std::dispatch::(i_sresp_select, s_mresp_accept, false); + } + + always_comb { + s_sresp_valid = $std::select::(i_sresp_select, m_sresp_valid); + s_sresp = $std::select::(i_sresp_select, m_sresp); + } + + for i in 0..MASTERS : g_master { + always_comb { + master_if[i].mresp_accept = m_mresp_accept[i]; + m_sresp_valid[i] = master_if[i].sresp_valid; + m_sresp[i] = master_if[i].get_packed_sresp(); + } + } +} diff --git a/veryl/pzcorebus_selector/pzcorebus_sresp_mux.veryl b/veryl/pzcorebus_selector/pzcorebus_sresp_mux.veryl new file mode 100644 index 0000000..80d88c9 --- /dev/null +++ b/veryl/pzcorebus_selector/pzcorebus_sresp_mux.veryl @@ -0,0 +1,44 @@ +//======================================== +// +// Copyright (c) 2026 PEZY Computing, K.K. +// +//======================================== +pub module pzcorebus_sresp_mux:: #( + param SLAVES : u32 = 2 , + param KIND : selector_kind = selector_kind::ONEHOT , + param SELECT_WIDTH: u32 = calc_select_width(SLAVES, KIND), +)( + i_sresp_select: input logic , + slave_if : modport pzcorebus_if::::slave_sresp[SLAVES], + master_if : modport pzcorebus_if::::master_sresp , +){ + import $std::selector_pkg::*; + + var s_mresp_accept: logic ; + var s_sresp_valid : logic ; + var m_mresp_accept: logic ; + var m_sresp_valid : logic ; + var m_sresp : PKG::pzcorebus_packed_sresp ; + + for i in 0..SLAVES :g_slave { + always_comb { + s_mresp_accept[i] = slave_if[i].mresp_accept; + slave_if[i].sresp_valid = s_sresp_valid[i]; + slave_if[i].put_packed_sresp(m_sresp); + } + } + + always_comb { + m_mresp_accept = $std::select::(i_sresp_select, s_mresp_accept); + } + + always_comb { + s_sresp_valid = $std::dispatch::(i_sresp_select, m_sresp_valid, false); + } + + always_comb { + master_if.mresp_accept = m_mresp_accept; + m_sresp_valid = master_if.sresp_valid; + m_sresp = master_if.get_packed_sresp(); + } +} diff --git a/veryl/pzcorebus_slicer/pzcorebus_slicer.veryl b/veryl/pzcorebus_slicer/pzcorebus_slicer.veryl new file mode 100644 index 0000000..758327c --- /dev/null +++ b/veryl/pzcorebus_slicer/pzcorebus_slicer.veryl @@ -0,0 +1,128 @@ +//======================================== +// +// Copyright (c) 2025 PEZY Computing, K.K. +// +//======================================== +pub module pzcorebus_slicer::#( + param STAGES : u32 = 1 , + param ASCENDING_ORDER: bbool = true , + param FULL_BANDWIDTH : bbool = true , + param DISABLE_MBFF : bbool = false , + param USE_RESET : bbool = true , + param MCMD_VALID : bbool = true , + param MCMD_STAGES : u32 = STAGES, + param MDATA_VALID : bbool = true , + param MDATA_STAGES : u32 = STAGES, + param SRESP_VALID : bbool = true , + param SRESP_STAGES : u32 = STAGES, +)( + i_clk : input clock , + i_rst : input reset , + slave_if : modport pzcorebus_if::::slave , + master_if: modport pzcorebus_if::::master, +){ + const BUS_CONFIG: pzcorebus_common_pkg::pzcorebus_config = PKG::BUS_CONFIG; + + var mcmd : PKG::pzcorebus_packed_mcmd<2>; + var mdata: PKG::pzcorebus_packed_mdata<2>; + var sresp: PKG::pzcorebus_packed_sresp<2>; + + always_comb { + mcmd[0] = slave_if.get_packed_mcmd(); + mdata[0] = slave_if.get_packed_mdata(); + } + + always_comb { + master_if.put_packed_mcmd(mcmd[1]); + master_if.put_packed_mdata(mdata[1]); + } + + always_comb { + sresp[1] = master_if.get_packed_sresp(); + } + + always_comb { + slave_if.put_packed_sresp(sresp[0]); + } + + if MCMD_VALID && MCMD_STAGES >= 1 :g_mcmd { + inst u_slicer: $std::slicer #( + TYPE : PKG::pzcorebus_packed_mcmd, + STAGES : MCMD_STAGES , + ASCENDING_ORDER: ASCENDING_ORDER , + FULL_BANDWIDTH : FULL_BANDWIDTH , + DISABLE_MBFF : DISABLE_MBFF , + USE_RESET : USE_RESET , + )( + i_clk : i_clk , + i_rst : i_rst , + o_ready: slave_if.scmd_accept , + i_valid: slave_if.mcmd_valid , + i_data : mcmd[0] , + i_ready: master_if.scmd_accept, + o_valid: master_if.mcmd_valid , + o_data : mcmd[1] , + ); + } else { + always_comb { + slave_if.scmd_accept = master_if.scmd_accept; + master_if.mcmd_valid = slave_if.mcmd_valid; + mcmd[1] = mcmd[0]; + } + } + + if MDATA_VALID + && MDATA_STAGES >= 1 + && BUS_CONFIG.profile != PKG::pzcorebus_profile::CSR :g_mdata + { + inst u_slicer: $std::slicer #( + TYPE : PKG::pzcorebus_packed_mdata, + STAGES : MDATA_STAGES , + ASCENDING_ORDER: ASCENDING_ORDER , + FULL_BANDWIDTH : FULL_BANDWIDTH , + DISABLE_MBFF : DISABLE_MBFF , + USE_RESET : USE_RESET , + )( + i_clk : i_clk , + i_rst : i_rst , + o_ready: slave_if.sdata_accept , + i_valid: slave_if.mdata_valid , + i_data : mdata[0] , + i_ready: master_if.sdata_accept, + o_valid: master_if.mdata_valid , + o_data : mdata[1] , + ); + } else { + always_comb { + slave_if.sdata_accept = master_if.sdata_accept; + master_if.mdata_valid = slave_if.mdata_valid; + mdata[1] = mdata[0]; + } + } + + if SRESP_VALID && SRESP_STAGES >= 1 :g_sresp { + inst u_slicer: $std::slicer #( + TYPE : PKG::pzcorebus_packed_sresp, + STAGES : SRESP_STAGES , + ASCENDING_ORDER: ASCENDING_ORDER , + FULL_BANDWIDTH : FULL_BANDWIDTH , + DISABLE_MBFF : DISABLE_MBFF , + USE_RESET : USE_RESET , + )( + i_clk : i_clk , + i_rst : i_rst , + o_ready: master_if.mresp_accept, + i_valid: master_if.sresp_valid , + i_data : sresp[1] , + i_ready: slave_if.mresp_accept , + o_valid: slave_if.sresp_valid , + o_data : sresp[0] , + ); + } else { + always_comb { + master_if.mresp_accept = slave_if.mresp_accept; + slave_if.sresp_valid = master_if.sresp_valid; + sresp[0] = sresp[1]; + } + } +} diff --git a/veryl/pzcorebus_switch/pzcorebus_1_to_m_switch.veryl b/veryl/pzcorebus_switch/pzcorebus_1_to_m_switch.veryl new file mode 100644 index 0000000..24419b7 --- /dev/null +++ b/veryl/pzcorebus_switch/pzcorebus_1_to_m_switch.veryl @@ -0,0 +1,100 @@ +pub module pzcorebus_1_to_m_switch:: #( + param MASTERS : u32 = 2 , + param ENABLE_BROADCAST : bbool = false , + param WAIT_FOR_MDATA : bbool = false , + param WAIT_FOR_MDATA_LAST : bbool = false , + param EXTERNAL_DECODE : bbool = false , + param SELECTOR_KIND : selector_kind = selector_kind::BINARY , + param SELECT_WIDTH : u32 = calc_select_width(MASTERS, SELECTOR_KIND), + param SELECT_LSB : u32 = PKG::BUS_CONFIG.id_width - SELECT_WIDTH , + param PRIORITY_ENABLE : bbool = false , + param PRIORITY_WIDTH : u32 = 1 , + param WEIGHT_ENABLE : bbool = false , + param WEIGHT_WIDTH : u32 = 1 , + param INITIAL_WEIGHT : bit = '1 , + param SLAVE_FIFO : bbool = false , + param SLAVE_FIFO_MCMD_DEPTH : u32 = 2 , + param SLAVE_FIFO_MDATA_DEPTH : u32 = 2 , + param SLAVE_FIFO_SRESP_DEPTH : u32 = 2 , + param MASTER_FIFO : bbool = false , + param MASTER_FIFO_MCMD_DEPTH : u32 = 2 , + param MASTER_FIFO_MDATA_DEPTH: u32 = 2 , + param MASTER_FIFO_SRESP_DEPTH: u32 = 2 , + param ALIGH_OUT : bbool = false , +)( + i_clk : input clock , + i_rst : input reset , + i_arbiter_kind : input pzbcm_arbiter_kind = pzbcm_arbiter_kind::ROUND_ROBIN, + i_arbiter_init : input logic = false , + i_arbiter_priority : input logic = '0 , + i_arbiter_weight_valid: input logic = false , + i_arbiter_weight : input logic = '0 , + o_mcmd : output PKG::pzcorebus_bundled_mcmd = _ , + i_mcmd_select : input logic = '0 , + slave_if : modport pzcorebus_if::::slave , + master_if : modport pzcorebus_if::::master[MASTERS] , +) { + import $std::selector_pkg::*; + import pzbcm_arbiter_pkg::pzbcm_arbiter_kind; + + inst slave_switch_if : pzcorebus_if:: ; + inst master_switch_if: pzcorebus_if::[MASTERS]; + + always_comb { + slave_if <> slave_switch_if.master; + } + + inst u_mreq_switch: pzcorebus_mreq_1_to_m_switch:: #( + MASTERS : MASTERS , + ENABLE_BROADCAST : ENABLE_BROADCAST , + WAIT_FOR_MDATA : WAIT_FOR_MDATA , + WAIT_FOR_MDATA_LAST : WAIT_FOR_MDATA_LAST , + EXTERNAL_DECODE : EXTERNAL_DECODE , + SELECTOR_KIND : SELECTOR_KIND , + SELECT_WIDTH : SELECT_WIDTH , + SELECT_LSB : SELECT_LSB , + SLAVE_FIFO : SLAVE_FIFO , + SLAVE_FIFO_MCMD_DEPTH : SLAVE_FIFO_MCMD_DEPTH , + SLAVE_FIFO_MDATA_DEPTH : SLAVE_FIFO_MDATA_DEPTH , + MASTER_FIFO : MASTER_FIFO , + MASTER_FIFO_MCMD_DEPTH : MASTER_FIFO_MCMD_DEPTH , + MASTER_FIFO_MDATA_DEPTH: MASTER_FIFO_MDATA_DEPTH, + ALIGH_OUT : ALIGH_OUT , + )( + i_clk : i_clk , + i_rst : i_rst , + o_mcmd : o_mcmd , + i_mcmd_select: i_mcmd_select , + slave_if : slave_switch_if , + master_if : master_switch_if, + ); + + inst u_sresp_switch: pzcorebus_sresp_1_to_m_switch:: #( + MASTERS : MASTERS , + PRIORITY_ENABLE : PRIORITY_ENABLE , + PRIORITY_WIDTH : PRIORITY_WIDTH , + WEIGHT_ENABLE : WEIGHT_ENABLE , + WEIGHT_WIDTH : WEIGHT_WIDTH , + INITIAL_WEIGHT : INITIAL_WEIGHT , + SLAVE_FIFO : SLAVE_FIFO , + SLAVE_FIFO_SRESP_DEPTH : SLAVE_FIFO_SRESP_DEPTH , + MASTER_FIFO : MASTER_FIFO , + MASTER_FIFO_SRESP_DEPTH: MASTER_FIFO_SRESP_DEPTH, + )( + i_clk : i_clk , + i_rst : i_rst , + i_arbiter_kind : i_arbiter_kind , + i_arbiter_init : i_arbiter_init , + i_arbiter_priority : i_arbiter_priority , + i_arbiter_weight_valid: i_arbiter_weight_valid, + i_arbiter_weight : i_arbiter_weight , + slave_if : slave_switch_if , + master_if : master_switch_if , + ); + + for i in 0..MASTERS :g_master { + always_comb { + master_switch_if[i].slave <> master_if[i]; + } + } +} diff --git a/veryl/pzcorebus_switch/pzcorebus_m_to_1_switch.veryl b/veryl/pzcorebus_switch/pzcorebus_m_to_1_switch.veryl new file mode 100644 index 0000000..303c15f --- /dev/null +++ b/veryl/pzcorebus_switch/pzcorebus_m_to_1_switch.veryl @@ -0,0 +1,121 @@ +//======================================== +// +// Copyright (c) 2026 PEZY Computing, K.K. +// +//======================================== +pub module pzcorebus_m_to_1_switch:: #( + param SLAVES : u32 = 2 , + param EXTERNAL_DECODE : bbool = false , + param WAIT_FOR_MDATA : bbool = false , + param WAIT_FOR_SRESP : bbool = false , + param PRIORITY_ENABLE : bbool = false , + param PRIORITY_WIDTH : u32 = 1 , + param WEIGHT_ENABLE : bbool = false , + param WEIGHT_WIDTH : u32 = 1 , + param INITIAL_WEIGHT : bit = '1 , + param SELECTOR_KIND : selector_kind = selector_kind::BINARY , + param SELECT_WIDTH : u32 = calc_select_width(SLAVES, SELECTOR_KIND), + param SELECT_LSB : u32 = PKG::BUS_CONFIG.id_width - SELECT_WIDTH , + param SLAVE_FIFO : bbool = false , + param SLAVE_FIFO_MCMD_DEPTH : u32 = 2 , + param SLAVE_FIFO_MDATA_DEPTH : u32 = 2 , + param SLAVE_FIFO_SRESP_DEPTH : u32 = 2 , + param MASTER_FIFO : bbool = false , + param MASTER_FIFO_MCMD_DEPTH : u32 = 2 , + param MASTER_FIFO_MDATA_DEPTH: u32 = 2 , + param MASTER_FIFO_SRESP_DEPTH: u32 = 2 , + param MASETR_ALIGNER : bbool = false , +)( + i_clk : input clock , + i_rst : input reset , + i_arbiter_kind : input pzbcm_arbiter_kind = pzbcm_arbiter_kind::ROUND_ROBIN, + i_arbiter_init : input logic = false , + i_arbiter_priority : input logic = '0 , + i_arbiter_weight_valid: input logic = false , + i_arbiter_weight : input logic = '0 , + o_sresp : output PKG::pzcorebus_bundled_sresp = _ , + i_sresp_select : input logic = '0 , + slave_if : modport pzcorebus_if::::slave[SLAVES] , + master_if : modport pzcorebus_if::::master , +) { + import $std::selector_pkg::*; + import pzbcm_arbiter_pkg::*; + + const SRESP_SELECTOR_KIND: selector_kind = if WAIT_FOR_SRESP ? selector_kind::ONEHOT : SELECTOR_KIND; + const SRESP_SELECT_WIDTH : u32 = if WAIT_FOR_SRESP ? SLAVES : SELECT_WIDTH ; + + inst slave_switch_if : pzcorebus_if::[SLAVES]; + inst mastre_switch_if: pzcorebus_if::; + + var sresp_last_ack: logic ; + var sresp_select : logic ; + var select : logic; + + for i in 0..SLAVES: g_slave { + always_comb { + slave_if[i] <> slave_switch_if[i].master; + } + } + + inst u_mreq_switch: pzcorebus_mreq_m_to_1_switch:: #( + SLAVES : SLAVES , + PRIORITY_ENABLE : PRIORITY_ENABLE , + PRIORITY_WIDTH : PRIORITY_WIDTH , + WEIGHT_ENABLE : WEIGHT_ENABLE , + WEIGHT_WIDTH : WEIGHT_WIDTH , + INITIAL_WEIGHT : INITIAL_WEIGHT , + WAIT_FOR_MDATA : WAIT_FOR_MDATA , + WAIT_FOR_SRESP : WAIT_FOR_SRESP , + SLAVE_FIFO : SLAVE_FIFO , + SLAVE_FIFO_MCMD_DEPTH : SLAVE_FIFO_MCMD_DEPTH , + SLAVE_FIFO_MDATA_DEPTH : SLAVE_FIFO_MDATA_DEPTH , + MASTER_FIFO : MASTER_FIFO , + MASTER_FIFO_MCMD_DEPTH : MASTER_FIFO_MCMD_DEPTH , + MASTER_FIFO_MDATA_DEPTH: MASTER_FIFO_MDATA_DEPTH, + MASTER_ALIGNER : MASETR_ALIGNER , + )( + i_clk : i_clk , + i_rst : i_rst , + i_arbiter_kind : i_arbiter_kind , + i_arbiter_init : i_arbiter_init , + i_arbiter_priority : i_arbiter_priority , + i_arbiter_weight_valid: i_arbiter_weight_valid, + i_arbiter_weight : i_arbiter_weight , + o_sresp_select : sresp_select , + i_sresp_last_ack : sresp_last_ack , + slave_if : slave_switch_if , + master_if : mastre_switch_if , + ); + + always_comb { + if WAIT_FOR_SRESP { + select = sresp_select as SRESP_SELECT_WIDTH; + } else { + select = i_sresp_select as SRESP_SELECT_WIDTH; + } + } + + inst u_sresp_switch: pzcorebus_sresp_m_to_1_switch:: #( + SLAVES : SLAVES , + EXTERNAL_DECODE : EXTERNAL_DECODE || WAIT_FOR_SRESP, + SELECTOR_KIND : SRESP_SELECTOR_KIND , + SELECT_WIDTH : SRESP_SELECT_WIDTH , + SELECT_LSB : SELECT_LSB , + SLAVE_FIFO : SLAVE_FIFO , + SLAVE_FIFO_SRESP_DEPTH : SLAVE_FIFO_SRESP_DEPTH , + MASTER_FIFO : MASTER_FIFO , + MASTER_FIFO_SRESP_DEPTH: MASTER_FIFO_SRESP_DEPTH , + )( + i_clk : i_clk , + i_rst : i_rst , + o_sresp : o_sresp , + i_sresp_select : select , + o_sresp_last_ack: sresp_last_ack , + slave_if : slave_switch_if , + master_if : mastre_switch_if, + ); + + always_comb { + mastre_switch_if.slave <> master_if; + } +} diff --git a/veryl/pzcorebus_switch/pzcorebus_mreq_1_to_m_switch.veryl b/veryl/pzcorebus_switch/pzcorebus_mreq_1_to_m_switch.veryl new file mode 100644 index 0000000..24ae1eb --- /dev/null +++ b/veryl/pzcorebus_switch/pzcorebus_mreq_1_to_m_switch.veryl @@ -0,0 +1,227 @@ +//======================================== +// +// Copyright (c) 2026 PEZY Computing, K.K. +// +//======================================== +pub module pzcorebus_mreq_1_to_m_switch:: #( + param MASTERS : u32 = 2 , + param ENABLE_BROADCAST : bbool = false , + param WAIT_FOR_MDATA : bbool = false , + param WAIT_FOR_MDATA_LAST : bbool = false , + param EXTERNAL_DECODE : bbool = false , + param SELECTOR_KIND : selector_kind = selector_kind::BINARY , + param SELECT_WIDTH : u32 = calc_select_width(MASTERS, SELECTOR_KIND), + param SELECT_LSB : u32 = PKG::BUS_CONFIG.id_width - SELECT_WIDTH , + param SLAVE_FIFO : bbool = false , + param SLAVE_FIFO_MCMD_DEPTH : u32 = 2 , + param SLAVE_FIFO_MDATA_DEPTH : u32 = 2 , + param MASTER_FIFO : bbool = false , + param MASTER_FIFO_MCMD_DEPTH : u32 = 2 , + param MASTER_FIFO_MDATA_DEPTH: u32 = 2 , + param ALIGH_OUT : bbool = false , +)( + i_clk : input clock , + i_rst : input reset , + o_mcmd : output PKG::pzcorebus_bundled_mcmd = _ , + i_mcmd_select: input logic = '0 , + slave_if : modport pzcorebus_if::::slave_mreq , + master_if : modport pzcorebus_if::::master_mreq[MASTERS], +) { + import $std::selector_pkg::*; + import pzcorebus_common_pkg::*; + + const BROADCAST: bbool = is_csr_profile(PKG::BUS_CONFIG) && ENABLE_BROADCAST; + +//-------------------------------------------------------------- +// Slave Mreq Alignment +//-------------------------------------------------------------- + inst aligner_if: pzcorebus_if::; + + if is_mem_profile(PKG::BUS_CONFIG) :g_slave_aligner { + inst u_aligner: pzcorebus_mreq_aligner_core:: #( + WAIT_FOR_DATA : WAIT_FOR_MDATA , + THROUGH_NO_DATA_COMMAND: !WAIT_FOR_MDATA_LAST , + SLAVE_FIFO : SLAVE_FIFO , + SLAVE_FIFO_MCMD_DEPTH : SLAVE_FIFO_MCMD_DEPTH , + SLAVE_FIFO_MDATA_DEPTH : SLAVE_FIFO_MDATA_DEPTH, + )( + i_clk : i_clk , + i_rst : i_rst , + slave_if : slave_if , + master_if: aligner_if, + ); + } else if SLAVE_FIFO { + inst u_fifo: pzcorebus_mreq_fifo:: #( + MCMD_DEPTH : SLAVE_FIFO_MCMD_DEPTH , + MDATA_DEPTH: SLAVE_FIFO_MDATA_DEPTH, + )( + i_clk : i_clk , + i_rst : i_rst , + slave_if : slave_if , + master_if: aligner_if, + ); + } else { + always_comb { + slave_if <> aligner_if.master_mreq; + } + } + +//-------------------------------------------------------------- +// Switch +//-------------------------------------------------------------- + inst switch_if: pzcorebus_if::[MASTERS]; + + var select : logic ; + var mcmd_select : logic ; + var mdata_select : logic ; + var scmd_accept : logic ; + var mcmd_valid : logic ; + var mcmd : PKG::pzcorebus_bundled_mcmd ; + var mcmd_broadcast: logic ; + var sdata_accept : logic ; + var mdata_valid : logic ; + var mdata : PKG::pzcorebus_bundled_mdata; + + if EXTERNAL_DECODE :g_select { + always_comb { + o_mcmd = aligner_if.get_mcmd(); + } + + always_comb { + select = i_mcmd_select; + } + } else { + always_comb { + o_mcmd = 0 as PKG::pzcorebus_bundled_mcmd; + } + + always_comb { + select = aligner_if.maddr[SELECT_LSB+:SELECT_WIDTH]; + } + } + + if SELECTOR_KIND == selector_kind::BINARY || !EXTERNAL_DECODE :g_mcmd_select { + always_comb { + for i in 0..MASTERS { + mcmd_select[i] = select == (i as SELECT_WIDTH); + } + } + } else { + always_comb { + mcmd_select = select; + } + } + + if is_mem_profile(PKG::BUS_CONFIG) :g_mdata_select { + var mdata_select_latched: logic; + + always_comb { + if aligner_if.mcmd_with_data_valid() { + mdata_select = mcmd_select; + } else { + mdata_select = mdata_select_latched; + } + } + + always_ff { + if_reset { + mdata_select_latched = '0; + } else if aligner_if.mcmd_with_data_valid() { + mdata_select_latched = mcmd_select; + } + } + } else { + always_comb { + mdata_select = '0; + } + } + + always_comb { + aligner_if.scmd_accept = &scmd_accept; + aligner_if.sdata_accept = |sdata_accept; + mcmd_valid = aligner_if.mcmd_valid; + mcmd = aligner_if.get_mcmd(); + mdata_valid = aligner_if.mdata_valid; + mdata = aligner_if.get_mdata(); + + if BROADCAST { + mcmd_broadcast = mcmd.mcmd == pzcorebus_mcmd::BROADCAST; + } else { + mcmd_broadcast = false; + } + } + + for i in 0..MASTERS :g_switch { + var mcmd_done : logic; + var mcmd_active: logic; + + always_comb { + mcmd_active = (!mcmd_done) && (mcmd_broadcast || mcmd_select[i]); + if mcmd_active { + scmd_accept[i] = switch_if[i].scmd_accept; + switch_if[i].mcmd_valid = mcmd_valid; + } else { + scmd_accept[i] = true; + switch_if[i].mcmd_valid = false; + } + switch_if[i].put_mcmd(mcmd); + + if mdata_select[i] { + sdata_accept[i] = switch_if[i].sdata_accept; + switch_if[i].mdata_valid = aligner_if.mdata_valid; + } else { + sdata_accept[i] = false; + switch_if[i].mdata_valid = false; + } + switch_if[i].put_mdata(mdata); + } + + if BROADCAST :g { + always_ff { + if_reset { + mcmd_done = false; + } else if aligner_if.mcmd_ack() { + mcmd_done = false; + } else if switch_if[i].mcmd_ack() { + mcmd_done = true; + } + } + } else { + always_comb { + mcmd_done = false; + } + } + } + +//-------------------------------------------------------------- +// Master Mreq Alignment +//-------------------------------------------------------------- + for i in 0..MASTERS :g_master_aligner { + if is_mem_profile(PKG::BUS_CONFIG) && ALIGH_OUT :g { + inst u_aligner: pzcorebus_mreq_aligner_core:: #( + SLAVE_FIFO : MASTER_FIFO , + SLAVE_FIFO_MCMD_DEPTH : MASTER_FIFO_MCMD_DEPTH , + SLAVE_FIFO_MDATA_DEPTH: MASTER_FIFO_MDATA_DEPTH, + )( + i_clk : i_clk , + i_rst : i_rst , + slave_if : switch_if[i], + master_if: master_if[i], + ); + } else if MASTER_FIFO { + inst u_fifo: pzcorebus_mreq_fifo:: #( + MCMD_DEPTH : MASTER_FIFO_MCMD_DEPTH , + MDATA_DEPTH: MASTER_FIFO_MDATA_DEPTH, + )( + i_clk : i_clk , + i_rst : i_rst , + slave_if : switch_if[i], + master_if: master_if[i], + ); + } else { + always_comb { + switch_if[i].slave_mreq <> master_if[i]; + } + } + } +} diff --git a/veryl/pzcorebus_switch/pzcorebus_mreq_m_to_1_switch.veryl b/veryl/pzcorebus_switch/pzcorebus_mreq_m_to_1_switch.veryl new file mode 100644 index 0000000..34dbf01 --- /dev/null +++ b/veryl/pzcorebus_switch/pzcorebus_mreq_m_to_1_switch.veryl @@ -0,0 +1,253 @@ +//======================================== +// +// Copyright (c) 2026 PEZY Computing, K.K. +// +//======================================== +pub module pzcorebus_mreq_m_to_1_switch:: #( + param SLAVES : u32 = 2 , + param PRIORITY_ENABLE : bbool = false, + param PRIORITY_WIDTH : u32 = 1 , + param WEIGHT_ENABLE : bbool = false, + param WEIGHT_WIDTH : u32 = 1 , + param INITIAL_WEIGHT : bit = '1 , + param WAIT_FOR_MDATA : bbool = false, + param WAIT_FOR_SRESP : bbool = false, + param SLAVE_FIFO : bbool = false, + param SLAVE_FIFO_MCMD_DEPTH : u32 = 2 , + param SLAVE_FIFO_MDATA_DEPTH : u32 = 2 , + param MASTER_FIFO : bbool = false, + param MASTER_FIFO_MCMD_DEPTH : u32 = 2 , + param MASTER_FIFO_MDATA_DEPTH: u32 = 2 , + param MASTER_ALIGNER : bbool = false, +)( + i_clk : input clock , + i_rst : input reset , + i_arbiter_kind : input pzbcm_arbiter_kind = pzbcm_arbiter_kind::ROUND_ROBIN, + i_arbiter_init : input logic = false , + i_arbiter_priority : input logic = '0 , + i_arbiter_weight_valid: input logic = false , + i_arbiter_weight : input logic = '0 , + o_sresp_select : output logic = _ , + i_sresp_last_ack : input logic = false , + slave_if : modport pzcorebus_if::::slave_mreq[SLAVES] , + master_if : modport pzcorebus_if::::master_mreq , +) { + import pzbcm_arbiter_pkg::*; + import pzcorebus_common_pkg::*; + import $std::selector_pkg::selector_kind; + +//-------------------------------------------------------------- +// Slave MReq Aligner +//-------------------------------------------------------------- + inst aligner_if: pzcorebus_if::[SLAVES]; + + for i in 0..SLAVES :g_slave_aligner { + if is_mem_profile(PKG::BUS_CONFIG) :g { + inst u_aligner: pzcorebus_mreq_aligner_core:: #( + WAIT_FOR_DATA : WAIT_FOR_MDATA , + THROUGH_NO_DATA_COMMAND: true , + SLAVE_FIFO : SLAVE_FIFO , + SLAVE_FIFO_MCMD_DEPTH : SLAVE_FIFO_MCMD_DEPTH , + SLAVE_FIFO_MDATA_DEPTH : SLAVE_FIFO_MDATA_DEPTH, + )( + i_clk : i_clk , + i_rst : i_rst , + slave_if : slave_if[i] , + master_if: aligner_if[i], + ); + } else if SLAVE_FIFO { + inst u_fifo: pzcorebus_mreq_fifo:: #( + MCMD_DEPTH : SLAVE_FIFO_MCMD_DEPTH , + MDATA_DEPTH: SLAVE_FIFO_MDATA_DEPTH, + )( + i_clk : i_clk , + i_rst : i_rst , + slave_if : slave_if[i] , + master_if: aligner_if[i], + ); + } else { + always_comb { + slave_if[i] <> aligner_if[i].master_mreq; + } + } + } + +//-------------------------------------------------------------- +// Switch +//-------------------------------------------------------------- + inst switch_if: pzcorebus_if::[2]; + + var mcmd_valid : logic; + var mcmd_grant : logic; + var mcmd_ack : logic ; + var mcmd_done : logic ; + var mdata_grant: logic; + var sresp_idle : logic ; + + for i in 0..SLAVES :g_mcmd { + always_comb { + mcmd_valid[i] = aligner_if[i].mcmd_valid; + } + } + + if is_mem_profile(PKG::BUS_CONFIG) :g_membus { + var done : logic<3> ; + var mdata_done: logic ; + var grant : logic; + + always_comb { + done[0] = switch_if[0].mcmd_with_data_ack() && switch_if[0].mdata_last_ack(); + done[1] = switch_if[0].mcmd_with_data_ack() && mdata_done; + done[2] = mcmd_done && switch_if[0].mdata_last_ack(); + } + + always_ff { + if_reset { + mcmd_done = false; + mdata_done = false; + } else if done != '0 { + mcmd_done = false; + mdata_done = false; + } else { + if switch_if[0].mcmd_with_data_ack() { + mcmd_done = true; + } + if switch_if[0].mdata_last_ack() { + mdata_done = true; + } + } + } + + always_comb { + if mcmd_done { + mdata_grant = grant; + } else { + mdata_grant = mcmd_grant; + } + } + + always_ff { + if_reset { + grant = '0; + } else if switch_if[0].mcmd_with_data_ack() { + grant = mcmd_grant; + } + } + } else { + always_comb { + mcmd_done = false; + mdata_grant = '0; + } + } + + always_comb { + mcmd_ack = switch_if[0].mcmd_ack(); + } + + inst u_arbiter: pzbcm_arbiter #( + REQUESTS : SLAVES , + ONEHOT_GRANT : true , + KEEP_RESULT : true , + FREE_WIDTH : 1 , + PRIORITY_ENABLE: PRIORITY_ENABLE, + PRIORITY_WIDTH : PRIORITY_WIDTH , + WEIGHT_ENABLE : WEIGHT_ENABLE , + WEIGHT_WIDTH : WEIGHT_WIDTH , + INITIAL_WEIGHT : INITIAL_WEIGHT , + )( + i_clk : i_clk , + i_rst : i_rst , + i_kind : i_arbiter_kind , + i_init : i_arbiter_init , + i_priority : i_arbiter_priority , + i_weight_valid: i_arbiter_weight_valid, + i_weight : i_arbiter_weight , + i_request : mcmd_valid , + o_grant : mcmd_grant , + i_free : mcmd_ack , + ); + + inst u_mreq_mux: pzcorebus_mreq_mux:: #( + SLAVES: SLAVES , + KIND : selector_kind::ONEHOT, + )( + i_mcmd_select : mcmd_grant , + i_mdata_select: mdata_grant , + slave_if : aligner_if , + master_if : switch_if[0], + ); + + always_comb { + switch_if[0].slave <> switch_if[1].master; + if !(sresp_idle && ((!mcmd_done) || switch_if[0].is_mcmd_no_data())) { + switch_if[0].scmd_accept = false; + switch_if[1].mcmd_valid = false; + } + } + + if WAIT_FOR_SRESP :g_sresp { + var sresp_select: logic; + + always_comb { + o_sresp_select = sresp_select; + } + + always_ff { + if_reset { + sresp_idle = true; + } else if i_sresp_last_ack { + sresp_idle = true; + } else if switch_if[1].mcmd_non_posted_ack() { + sresp_idle = false; + } + } + + always_ff { + if_reset { + sresp_select = '0; + } else if switch_if[1].mcmd_non_posted_ack() { + sresp_select = mcmd_grant; + } + } + } else { + always_comb { + o_sresp_select = '0; + } + + always_comb { + sresp_idle = true; + } + } + +//-------------------------------------------------------------- +// Master MReq Alignment +//-------------------------------------------------------------- + if is_mem_profile(PKG::BUS_CONFIG) && MASTER_ALIGNER :g_master_aligner { + inst u_aligner: pzcorebus_mreq_aligner_core:: #( + WAIT_FOR_DATA : WAIT_FOR_MDATA , + THROUGH_NO_DATA_COMMAND: true , + SLAVE_FIFO : MASTER_FIFO , + SLAVE_FIFO_MCMD_DEPTH : MASTER_FIFO_MCMD_DEPTH , + SLAVE_FIFO_MDATA_DEPTH : MASTER_FIFO_MDATA_DEPTH, + )( + i_clk : i_clk , + i_rst : i_rst , + slave_if : switch_if[1], + master_if: master_if , + ); + } else if MASTER_FIFO { + inst u_fifo: pzcorebus_mreq_fifo:: #( + MCMD_DEPTH : MASTER_FIFO_MCMD_DEPTH , + MDATA_DEPTH: MASTER_FIFO_MDATA_DEPTH, + )( + i_clk : i_clk , + i_rst : i_rst , + slave_if : switch_if[1], + master_if: master_if , + ); + } else { + always_comb { + switch_if[1].slave_mreq <> master_if; + } + } +} diff --git a/veryl/pzcorebus_switch/pzcorebus_sresp_1_to_m_switch.veryl b/veryl/pzcorebus_switch/pzcorebus_sresp_1_to_m_switch.veryl new file mode 100644 index 0000000..6796f86 --- /dev/null +++ b/veryl/pzcorebus_switch/pzcorebus_sresp_1_to_m_switch.veryl @@ -0,0 +1,121 @@ +//======================================== +// +// Copyright (c) 2026 PEZY Computing, K.K. +// +//======================================== +pub module pzcorebus_sresp_1_to_m_switch:: #( + param MASTERS : u32 = 2 , + param PRIORITY_ENABLE : bbool = false, + param PRIORITY_WIDTH : u32 = 1 , + param WEIGHT_ENABLE : bbool = false, + param WEIGHT_WIDTH : u32 = 1 , + param INITIAL_WEIGHT : bit = '1 , + param SLAVE_FIFO : bbool = false, + param SLAVE_FIFO_SRESP_DEPTH : u32 = 2 , + param MASTER_FIFO : bbool = false, + param MASTER_FIFO_SRESP_DEPTH: u32 = 2 , +)( + i_clk : input clock , + i_rst : input reset , + i_arbiter_kind : input pzbcm_arbiter_kind = pzbcm_arbiter_kind::ROUND_ROBIN, + i_arbiter_init : input logic = false , + i_arbiter_priority : input logic = '0 , + i_arbiter_weight_valid: input logic = false , + i_arbiter_weight : input logic = '0 , + slave_if : modport pzcorebus_if::::slave_sresp , + master_if : modport pzcorebus_if::::master_sresp[MASTERS] , +) { + import pzbcm_arbiter_pkg::*; + import $std::selector_pkg::selector_kind; + +//-------------------------------------------------------------- +// Slave FIFO +//-------------------------------------------------------------- + inst fifo_if: pzcorebus_if::; + + if SLAVE_FIFO :g_slave_fifo { + inst u_fifo: pzcorebus_sresp_fifo:: #( + SRESP_DEPTH: SLAVE_FIFO_SRESP_DEPTH, + )( + i_clk : i_clk , + i_rst : i_rst , + slave_if : slave_if, + master_if: fifo_if , + ); + } else { + always_comb { + slave_if <> fifo_if.master_sresp; + } + } + +//-------------------------------------------------------------- +// Switch +//-------------------------------------------------------------- + inst switch_if: pzcorebus_if::[MASTERS]; + + var sresp_valid: logic; + var sresp_grant: logic; + var sresp_free : logic ; + + for i in 0..MASTERS :g_sresp_valid { + always_comb { + sresp_valid[i] = switch_if[i].sresp_valid; + } + } + + always_comb { + sresp_free = fifo_if.sresp_sublast_ack(); + } + + inst u_arbiter: pzbcm_arbiter #( + REQUESTS : MASTERS , + ONEHOT_GRANT : true , + KEEP_RESULT : true , + FREE_WIDTH : 1 , + PRIORITY_ENABLE: PRIORITY_ENABLE, + PRIORITY_WIDTH : PRIORITY_WIDTH , + WEIGHT_ENABLE : WEIGHT_ENABLE , + WEIGHT_WIDTH : WEIGHT_WIDTH , + INITIAL_WEIGHT : INITIAL_WEIGHT , + )( + i_clk : i_clk , + i_rst : i_rst , + i_kind : i_arbiter_kind , + i_init : i_arbiter_init , + i_priority : i_arbiter_priority , + i_weight_valid: i_arbiter_weight_valid, + i_weight : i_arbiter_weight , + i_request : sresp_valid , + o_grant : sresp_grant , + i_free : sresp_free , + ); + + inst u_switch: pzcorebus_sresp_demux:: #( + MASTERS: MASTERS , + KIND : selector_kind::ONEHOT, + )( + i_sresp_select: sresp_grant, + slave_if : fifo_if , + master_if : switch_if , + ); + +//-------------------------------------------------------------- +// Master FIFO +//-------------------------------------------------------------- + for i in 0..MASTERS :g_master_fifo { + if MASTER_FIFO :g { + inst u_fifo: pzcorebus_sresp_fifo:: #( + SRESP_DEPTH: MASTER_FIFO_SRESP_DEPTH, + )( + i_clk : i_clk , + i_rst : i_rst , + slave_if : switch_if[i], + master_if: master_if[i], + ); + } else { + always_comb { + switch_if[i].slave_sresp <> master_if[i]; + } + } + } +} diff --git a/veryl/pzcorebus_switch/pzcorebus_sresp_m_to_1_switch.veryl b/veryl/pzcorebus_switch/pzcorebus_sresp_m_to_1_switch.veryl new file mode 100644 index 0000000..6b29ae6 --- /dev/null +++ b/veryl/pzcorebus_switch/pzcorebus_sresp_m_to_1_switch.veryl @@ -0,0 +1,104 @@ +//======================================== +// +// Copyright (c) 2026 PEZY Computing, K.K. +// +//======================================== +pub module pzcorebus_sresp_m_to_1_switch:: #( + param SLAVES : u32 = 2 , + param EXTERNAL_DECODE : bbool = false , + param SELECTOR_KIND : selector_kind = selector_kind::BINARY , + param SELECT_WIDTH : u32 = calc_select_width(SLAVES, SELECTOR_KIND), + param SELECT_LSB : u32 = PKG::BUS_CONFIG.id_width - SELECT_WIDTH , + param SLAVE_FIFO : bbool = false , + param SLAVE_FIFO_SRESP_DEPTH : u32 = 2 , + param MASTER_FIFO : bbool = false , + param MASTER_FIFO_SRESP_DEPTH: u32 = 2 , +)( + i_clk : input clock , + i_rst : input reset , + o_sresp : output PKG::pzcorebus_bundled_sresp = _ , + i_sresp_select : input logic = '0 , + o_sresp_last_ack: output logic = _ , + slave_if : modport pzcorebus_if::::slave_sresp[SLAVES], + master_if : modport pzcorebus_if::::master_sresp , +){ + import $std::selector_pkg::*; + +//-------------------------------------------------------------- +// Slave FIFO +//-------------------------------------------------------------- + inst fifo_if: pzcorebus_if::[SLAVES]; + + for i in 0..SLAVES :g_slave_fifo { + if SLAVE_FIFO : g { + inst u_fifo: pzcorebus_sresp_fifo:: #( + SRESP_DEPTH: SLAVE_FIFO_SRESP_DEPTH, + )( + i_clk : i_clk , + i_rst : i_rst , + slave_if : slave_if[i], + master_if: fifo_if[i] , + ); + } else { + always_comb { + slave_if[i] <> fifo_if[i].master_sresp; + } + } + } + +//-------------------------------------------------------------- +// Switch +//-------------------------------------------------------------- + inst switch_if : pzcorebus_if::; + var sresp_select: logic; + + always_comb { + o_sresp_last_ack = switch_if.sresp_last_ack(); + } + + if EXTERNAL_DECODE :g_sresp_select { + always_comb { + o_sresp = switch_if.get_sresp(); + } + + always_comb { + sresp_select = i_sresp_select; + } + } else { + always_comb { + o_sresp = 0 as PKG::pzcorebus_bundled_sresp; + } + + always_comb { + sresp_select = switch_if.sid[SELECT_LSB+:SELECT_WIDTH]; + } + } + + inst u_switch: pzcorebus_sresp_mux:: #( + SLAVES : SLAVES , + KIND : SELECTOR_KIND, + SELECT_WIDTH: SELECT_WIDTH , + )( + i_sresp_select: sresp_select, + slave_if : fifo_if , + master_if : switch_if , + ); + +//-------------------------------------------------------------- +// Master FIFO +//-------------------------------------------------------------- + if MASTER_FIFO : g_master_fifo { + inst u_fifo: pzcorebus_sresp_fifo:: #( + SRESP_DEPTH: MASTER_FIFO_SRESP_DEPTH, + )( + i_clk : i_clk , + i_rst : i_rst , + slave_if : switch_if, + master_if: master_if, + ); + } else { + always_comb { + switch_if.slave_sresp <> master_if; + } + } +} diff --git a/veryl/pzhsbus_common/pzhsbus_if.veryl b/veryl/pzhsbus_common/pzhsbus_if.veryl new file mode 100644 index 0000000..7b596e9 --- /dev/null +++ b/veryl/pzhsbus_common/pzhsbus_if.veryl @@ -0,0 +1,31 @@ +//======================================== +// +// Copyright (c) 2025 PEZY Computing, K.K. +// +//======================================== +pub interface pzhsbus_if:: { + var ready : logic; + var valid : logic; + var payload: T ; + + function ack() -> logic { + return ready && valid; + } + + modport master { + ready : input , + valid : output, + payload: output, + ack : import, + } + + modport slave { + ack: import, + ..converse(master) + } + + modport monitor { + ack: import, + ..input + } +} diff --git a/veryl/pzhsbus_fifo/pzhsbus_fifo.veryl b/veryl/pzhsbus_fifo/pzhsbus_fifo.veryl new file mode 100644 index 0000000..f04e1cf --- /dev/null +++ b/veryl/pzhsbus_fifo/pzhsbus_fifo.veryl @@ -0,0 +1,61 @@ +//======================================== +// +// Copyright (c) 2025 PEZY Computing, K.K. +// +//======================================== +pub module pzhsbus_fifo :: #( + param DEPTH : u32 = 8 , + param THRESHOLD : u32 = DEPTH , + param FLAG_FF_OUT : bbool = true , + param DATA_FF_OUT : bbool = true , + param RESET_RAM : bbool = false , + param CLEAR_DATA : bbool = false , + param RESET_DATA_FF: bbool = true , + const COUTNER_WIDTH: u32 = $clog2(DEPTH + 1), +)( + i_clk : input clock , + i_rst : input reset , + i_clear : input logic = false, + o_empty : output logic = _ , + o_almost_full: output logic = _ , + o_full : output logic = _ , + o_word_count : output logic = _ , + slave_if : modport pzhsbus_if::::slave , + master_if : modport pzhsbus_if::::master , +){ + var status: logic<3>; + + always_comb { + o_empty = status[0]; + o_almost_full = status[1]; + o_full = status[2]; + } + + always_comb { + slave_if.ready = !status[2]; + master_if.valid = !status[0]; + } + + inst u_fifo: $std::fifo #( + TYPE : T , + DEPTH : DEPTH , + THRESHOLD : THRESHOLD , + FLAG_FF_OUT : FLAG_FF_OUT , + DATA_FF_OUT : DATA_FF_OUT , + RESET_RAM : RESET_RAM , + CLEAR_DATA : CLEAR_DATA , + RESET_DATA_FF: RESET_DATA_FF, + )( + i_clk : i_clk , + i_rst : i_rst , + i_clear : i_clear , + o_empty : status[0] , + o_almost_full: status[1] , + o_full : status[2] , + o_word_count : o_word_count , + i_push : slave_if.valid , + i_data : slave_if.payload , + i_pop : master_if.ready , + o_data : master_if.payload, + ); +} diff --git a/veryl/pzhsbus_selector/pzhsbus_demux.veryl b/veryl/pzhsbus_selector/pzhsbus_demux.veryl new file mode 100644 index 0000000..5a4e4c9 --- /dev/null +++ b/veryl/pzhsbus_selector/pzhsbus_demux.veryl @@ -0,0 +1,49 @@ +//======================================== +// +// Copyright (c) 2025 PEZY Computing, K.K. +// +//======================================== +pub module pzhsbus_demux:: #( + param MASTERS : u32 = 2 , + param SELECTOR_KIND: selector_kind = selector_kind::ONEHOT , + const SELECT_WIDTH : u32 = calc_select_width(MASTERS, SELECTOR_KIND), +)( + i_select : input logic , + slave_if : modport pzhsbus_if::::slave , + master_if: modport pzhsbus_if::::master[MASTERS], +) { + import $std::selector_pkg::*; + + var ready: logic; + var valid: logic; + + if SELECTOR_KIND == selector_kind::VECTOR :g_selector { + always_comb { + slave_if.ready = '0; + valid = '0; + for i in 0..SELECT_WIDTH { + if i_select[i] { + slave_if.ready = ready[i]; + valid[i] = slave_if.valid; + break; + } + } + } + } else { + always_comb { + slave_if.ready = $std::select::(i_select, ready); + } + + always_comb { + valid = $std::dispatch::(i_select, slave_if.valid, false); + } + } + + for i in 0..MASTERS :g { + always_comb { + ready[i] = master_if[i].ready; + master_if[i].valid = valid[i]; + master_if[i].payload = slave_if.payload; + } + } +} diff --git a/veryl/pzhsbus_selector/pzhsbus_mux.veryl b/veryl/pzhsbus_selector/pzhsbus_mux.veryl new file mode 100644 index 0000000..326a2c5 --- /dev/null +++ b/veryl/pzhsbus_selector/pzhsbus_mux.veryl @@ -0,0 +1,53 @@ +//======================================== +// +// Copyright (c) 2022 PEZY Computing, K.K. +// +//======================================== +pub module pzhsbus_mux:: #( + param SLAVES : u32 = 2 , + param SELECTOR_KIND: selector_kind = selector_kind::ONEHOT , + const SELECT_WIDTH : u32 = calc_select_width(SLAVES, SELECTOR_KIND), +)( + i_select : input logic , + slave_if : modport pzhsbus_if::::slave[SLAVES], + master_if: modport pzhsbus_if::::master , +) { + import $std::selector_pkg::*; + + var ready : logic; + var valid : logic; + var payload: T ; + + for i in 0..SLAVES :g { + always_comb { + slave_if[i].ready = ready[i]; + valid[i] = slave_if[i].valid; + payload[i] = slave_if[i].payload; + } + } + + if SELECTOR_KIND == selector_kind::VECTOR :g_selector { + always_comb { + ready = '0; + master_if.valid = '0; + master_if.payload = 0 as T; + for i in 0..SLAVES { + if i_select[i] { + ready[i] = master_if.ready; + master_if.valid = valid[i]; + master_if.payload = payload[i]; + break; + } + } + } + } else { + always_comb { + ready = $std::dispatch::(i_select, master_if.ready, false); + } + + always_comb { + master_if.valid = $std::select::(i_select, valid); + master_if.payload = $std::select::(i_select, payload); + } + } +} diff --git a/veryl/pzhsbus_slicer/pzhsbus_slicer.veryl b/veryl/pzhsbus_slicer/pzhsbus_slicer.veryl new file mode 100644 index 0000000..6e9491d --- /dev/null +++ b/veryl/pzhsbus_slicer/pzhsbus_slicer.veryl @@ -0,0 +1,35 @@ +//======================================== +// +// Copyright (c) 2025 PEZY Computing, K.K. +// +//======================================== +pub module pzhsbus_slicer:: #( + param STAGES : u32 = 1 , + param ASCENDING_ORDER: bbool = true , + param FULL_BANDWIDTH : bbool = true , + param DISABLE_MBFF : bbool = false, + param USE_RESET : bbool = true , +)( + i_clk : input clock , + i_rst : input reset , + slave_if : modport pzhsbus_if::::slave , + master_if: modport pzhsbus_if::::master, +) { + inst u_slicer: $std::slicer #( + TYPE : T , + STAGES : STAGES , + ASCENDING_ORDER: ASCENDING_ORDER, + FULL_BANDWIDTH : FULL_BANDWIDTH , + DISABLE_MBFF : DISABLE_MBFF , + USE_RESET : USE_RESET , + )( + i_clk : i_clk , + i_rst : i_rst , + o_ready: slave_if.ready , + i_valid: slave_if.valid , + i_data : slave_if.payload , + i_ready: master_if.ready , + o_valid: master_if.valid , + o_data : master_if.payload, + ); +} From 580174466dbead483626eedb7d1e06f492f667e4 Mon Sep 17 00:00:00 2001 From: Taichi Ishitani Date: Wed, 17 Jun 2026 18:30:08 +0900 Subject: [PATCH 2/2] add WA for generated filelist issue (refs: veryl-lang/veryl#2850) --- veryl/pzcorebus_common/pzcorebus_utils_pkg.veryl | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/veryl/pzcorebus_common/pzcorebus_utils_pkg.veryl b/veryl/pzcorebus_common/pzcorebus_utils_pkg.veryl index 9431261..6c239fa 100644 --- a/veryl/pzcorebus_common/pzcorebus_utils_pkg.veryl +++ b/veryl/pzcorebus_common/pzcorebus_utils_pkg.veryl @@ -4,6 +4,8 @@ // //======================================== pub package pzcorebus_utils_pkg:: { + import $std::utils::clog2_clipped; + const IS_CSR : bbool = pzcorebus_common_pkg::is_csr_profile(PKG::BUS_CONFIG); const IS_MEM : bbool = pzcorebus_common_pkg::is_mem_profile(PKG::BUS_CONFIG); const IS_MEM_H: bbool = pzcorebus_common_pkg::is_mem_h_profile(PKG::BUS_CONFIG); @@ -81,7 +83,7 @@ pub package pzcorebus_utils_pkg:: { mlength: input PKG::pzcorebus_mlength, ) -> PKG::pzcorebus_mlength_unpacked { const OFFSET_LSB : u16 = $clog2(PKG::BUS_CONFIG.unit_data_width) - 3; - const OFFSET_WIDTH: u16 = $std::utils::clog2_clipped(PKG::BUS_CONFIG.data_size, 1); + const OFFSET_WIDTH: u16 = clog2_clipped(PKG::BUS_CONFIG.data_size, 1); var offset: logic; if PKG::BUS_CONFIG.data_size == 1 || is_mcmd_message(mcmd) || is_mcmd_atomic(mcmd) { @@ -101,14 +103,14 @@ pub package pzcorebus_utils_pkg:: { if IS_CSR { return 1 as PKG::pzcorebus_mburst_length; } else { - var mlength_unpaced: PKG::pzcorebus_mlength_unpacked; + var mlength_aligned: PKG::pzcorebus_mlength_unpacked; - mlength_unpaced = get_mlength_unpacked(mcmd, mlength); + mlength_aligned = get_mlength_aligned(mcmd, maddr, mlength); if PKG::BUS_CONFIG.data_size >: 1 { - mlength_unpaced += ((PKG::BUS_CONFIG.data_size - 1) as PKG::pzcorebus_mlength_unpacked); + mlength_aligned += ((PKG::BUS_CONFIG.data_size - 1) as PKG::pzcorebus_mlength_unpacked); } - return (mlength_unpaced / PKG::BUS_CONFIG.data_size) as PKG::pzcorebus_mburst_length; + return (mlength_aligned / PKG::BUS_CONFIG.data_size) as PKG::pzcorebus_mburst_length; } } }