diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a066c12..9c89cd77 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,6 +43,8 @@ jobs: secrets: inherit deploy: + permissions: + contents: write needs: build if: github.event_name == 'push' uses: ./.github/workflows/deploy.yml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 650115ce..47b8d32f 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -9,12 +9,36 @@ name: deploy on: workflow_call: + inputs: + IDMA_BACKEND_IDS: + description: Backend variants to generate. + required: false + type: string + default: "rw_axi r_obi_w_axi r_axi_w_obi rw_axi_rw_axis rw_obi r_obi_rw_init_w_axi r_axi_rw_init_rw_obi rw_axi_rw_init_rw_obi" + IDMA_REG_CPUIF: + description: PeakRDL CPU interface used for generated register frontends. + required: false + type: string + default: "apb4-flat" workflow_dispatch: + inputs: + IDMA_BACKEND_IDS: + description: Backend variants to generate. + required: false + type: string + default: "rw_axi r_obi_w_axi r_axi_w_obi rw_axi_rw_axis rw_obi r_obi_rw_init_w_axi r_axi_rw_init_rw_obi rw_axi_rw_init_rw_obi" + IDMA_REG_CPUIF: + description: PeakRDL CPU interface used for generated register frontends. + required: false + type: string + default: "apb4-flat" jobs: deploy: runs-on: ubuntu-latest + permissions: + contents: write steps: - name: Checkout @@ -36,7 +60,10 @@ jobs: version: 0.32.0 - name: Build hardware - run: uv run --locked make -B idma_hw_all + run: | + uv run --locked make -B idma_hw_all idma_sw_all \ + IDMA_BACKEND_IDS="${{ inputs.IDMA_BACKEND_IDS }}" \ + IDMA_REG_CPUIF="${{ inputs.IDMA_REG_CPUIF }}" - name: Deploy generated files run: | diff --git a/idma.mk b/idma.mk index 8e6bb18f..f84543d7 100644 --- a/idma.mk +++ b/idma.mk @@ -60,6 +60,7 @@ IDMA_FE_IDS ?= $(IDMA_BASE_FE_IDS) $(IDMA_ADD_FE_IDS) # iDMA paths IDMA_UTIL_DIR := $(IDMA_ROOT)/util IDMA_RTL_DIR := $(IDMA_ROOT)/target/rtl +IDMA_SW_DIR := $(IDMA_ROOT)/target/sw # job file IDMA_JOBS_JSON := jobs/jobs.json @@ -233,6 +234,21 @@ $(IDMA_HTML_DIR)/regs/idma_reg%d_reg/index.html: $(IDMA_HTML_DIR)/regs/idma_desc64_reg/index.html: $(PEAKRDL) html $(IDMA_FE_DIR)/desc64/idma_desc64_reg.rdl -o $(IDMA_HTML_DIR)/regs/idma_desc64_reg +# C header +$(IDMA_SW_DIR)/idma_reg%d_regs.h: + $(PEAKRDL) c-header $(IDMA_FE_DIR)/reg/idma_reg.rdl -o $@ \ + -P SysAddrWidth=$(call regwidth,$*) \ + -P NumDims=$(call dimension,$*) \ + -P Log2NumDims=$(call log2dimension,$(call dimension,$*)) + + +$(IDMA_SW_DIR)/idma_reg%d_raw_regs.h: + $(PEAKRDL) raw-header $(IDMA_FE_DIR)/reg/idma_reg.rdl -o $@ \ + --format c \ + -P SysAddrWidth=$(call regwidth,$*) \ + -P NumDims=$(call dimension,$*) \ + -P Log2NumDims=$(call log2dimension,$(call dimension,$*)) + idma_reg_clean: rm -rf $(IDMA_HTML_DIR)/regs rm -f $(IDMA_RTL_DIR)/*_reg_top.sv @@ -247,6 +263,11 @@ IDMA_RTL_ALL += $(foreach Y,$(IDMA_FE_REGS),$(IDMA_RTL_DIR)/idma_$Y_addrmap_ IDMA_RTL_ALL += $(foreach Y,$(IDMA_FE_REGS),$(IDMA_RTL_DIR)/idma_$Y_top.sv) IDMA_RTL_DOC_ALL += $(foreach Y,$(IDMA_FE_REGS),$(IDMA_HTML_DIR)/regs/idma_$Y_reg/index.html) +# C headers +IDMA_SW_ALL += $(foreach Y,$(IDMA_FE_IDS),$(IDMA_SW_DIR)/idma_$Y_regs.h) + +# C headers with the "raw-header" plugin +IDMA_SW_ALL += $(foreach Y,$(IDMA_FE_IDS),$(IDMA_SW_DIR)/idma_$Y_raw_regs.h) # --------------- # RTL assembly @@ -549,9 +570,9 @@ idma_nonfree_clean: # Misc Clean # -------------- -.PHONY: idma_clean_all idma_clean idma_misc_clean +.PHONY: idma_clean_all idma_clean idma_misc_clean idma_sw_clean -idma_clean_all idma_clean: idma_rtl_clean idma_reg_clean idma_pickle_clean idma_sim_clean idma_vcs_clean idma_verilator_clean idma_spinx_doc_clean idma_trace_clean +idma_clean_all idma_clean: idma_rtl_clean idma_reg_clean idma_pickle_clean idma_sim_clean idma_vcs_clean idma_verilator_clean idma_spinx_doc_clean idma_trace_clean idma_sw_clean idma_misc_clean: rm -rf scripts/__pycache__ @@ -562,6 +583,9 @@ idma_misc_clean: idma_nuke: idma_clean idma_nonfree_clean rm -rf .bender +idma_sw_clean: + rm -rf IDMA_SW_DIR/*.h + # -------------- # Phony Targets @@ -575,6 +599,8 @@ idma_pickle_all: $(IDMA_PICKLE_ALL) idma_hw_all: $(IDMA_FULL_RTL) $(IDMA_INCLUDE_ALL) $(IDMA_FULL_TB) $(IDMA_HJSON_ALL) $(IDMA_WAVE_ALL) +idma_sw_all: $(IDMA_SW_ALL) + idma_sim_all: $(IDMA_VCS_DIR)/compile.sh $(IDMA_VSIM_DIR)/compile.tcl idma_all: idma_hw_all idma_sim_all idma_doc_all idma_pickle_all diff --git a/pyproject.toml b/pyproject.toml index a2ccfcdb..5eb63a5d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,4 +20,5 @@ dependencies = [ "pylint", "peakrdl>=1.5.0", "peakrdl-rawheader>=0.2.4", + "peakrdl-cheader>=1.1.0", ] diff --git a/src/frontend/reg/tpl/idma_reg.sv.tpl b/src/frontend/reg/tpl/idma_reg.sv.tpl index a1ea9175..b5fb29a5 100644 --- a/src/frontend/reg/tpl/idma_reg.sv.tpl +++ b/src/frontend/reg/tpl/idma_reg.sv.tpl @@ -95,20 +95,19 @@ module idma_${identifier} #( idma_${identifier}_reg_pkg::idma_reg__in_t dma_hw2reg [NumRegs-1:0]; // arbitration output - dma_req_t [NumRegs-1:0] arb_dma_req; - logic [NumRegs-1:0] arb_valid; - logic [NumRegs-1:0] arb_ready; + typedef struct packed { + dma_req_t req; + stream_t stream_idx; + } arb_payload_t; - always_comb begin - stream_idx_o = '0; - for (int r = 0; r < NumRegs; r++) begin - for (int c = 0; c < NumStreams; c++) begin - if (dma_reg2hw[r].next_id[c].req && !dma_reg2hw[r].next_id[c].req_is_wr) begin - stream_idx_o = c; - end - end - end - end + arb_payload_t [NumRegs-1:0] arb_payload; + arb_payload_t arb_payload_out; + stream_t [NumRegs-1:0] arb_stream_idx; + logic [NumRegs-1:0] arb_valid; + logic [NumRegs-1:0] arb_ready; + + assign dma_req_o = arb_payload_out.req; + assign stream_idx_o = arb_payload_out.stream_idx; // generate the registers for (genvar i = 0; i < NumRegs; i++) begin : gen_core_regs @@ -181,8 +180,12 @@ module idma_${identifier} #( always_comb begin : proc_launch read_happens = 1'b0; + arb_stream_idx[i] = '0; for (int c = 0; c < NumStreams; c++) begin - read_happens |= dma_reg2hw[i].next_id[c].req & ~dma_reg2hw[i].next_id[c].req_is_wr; + if (dma_reg2hw[i].next_id[c].req & ~dma_reg2hw[i].next_id[c].req_is_wr) begin + read_happens = 1'b1; + arb_stream_idx[i] = stream_t'(c); + end end arb_valid[i] = read_happens; end @@ -190,51 +193,52 @@ module idma_${identifier} #( // assign request struct always_comb begin : proc_hw_req_conv // all fields are zero per default - arb_dma_req[i] = '0; + arb_payload[i] = '0; + arb_payload[i].stream_idx = arb_stream_idx[i]; // address and length % if bit_width == '32': - arb_dma_req[i]${sep}length = dma_reg2hw[i].length[0].length.value; - arb_dma_req[i]${sep}src_addr = dma_reg2hw[i].src_addr[0].src_addr.value; - arb_dma_req[i]${sep}dst_addr = dma_reg2hw[i].dst_addr[0].dst_addr.value; + arb_payload[i].req${sep}length = dma_reg2hw[i].length[0].length.value; + arb_payload[i].req${sep}src_addr = dma_reg2hw[i].src_addr[0].src_addr.value; + arb_payload[i].req${sep}dst_addr = dma_reg2hw[i].dst_addr[0].dst_addr.value; % else: - arb_dma_req[i]${sep}length = {dma_reg2hw[i].length[1].length.value, dma_reg2hw[i].length[0].length.value}; - arb_dma_req[i]${sep}src_addr = {dma_reg2hw[i].src_addr[1].src_addr.value, dma_reg2hw[i].src_addr[0].src_addr.value}; - arb_dma_req[i]${sep}dst_addr = {dma_reg2hw[i].dst_addr[1].dst_addr.value, dma_reg2hw[i].dst_addr[0].dst_addr.value}; + arb_payload[i].req${sep}length = {dma_reg2hw[i].length[1].length.value, dma_reg2hw[i].length[0].length.value}; + arb_payload[i].req${sep}src_addr = {dma_reg2hw[i].src_addr[1].src_addr.value, dma_reg2hw[i].src_addr[0].src_addr.value}; + arb_payload[i].req${sep}dst_addr = {dma_reg2hw[i].dst_addr[1].dst_addr.value, dma_reg2hw[i].dst_addr[0].dst_addr.value}; % endif // Protocols - arb_dma_req[i]${sep}opt.src_protocol = idma_pkg::protocol_e'(dma_reg2hw[i].conf.src_protocol.value); - arb_dma_req[i]${sep}opt.dst_protocol = idma_pkg::protocol_e'(dma_reg2hw[i].conf.dst_protocol.value); + arb_payload[i].req${sep}opt.src_protocol = idma_pkg::protocol_e'(dma_reg2hw[i].conf.src_protocol.value); + arb_payload[i].req${sep}opt.dst_protocol = idma_pkg::protocol_e'(dma_reg2hw[i].conf.dst_protocol.value); // Current backend only supports incremental burst - arb_dma_req[i]${sep}opt.src.burst = axi_pkg::BURST_INCR; - arb_dma_req[i]${sep}opt.dst.burst = axi_pkg::BURST_INCR; + arb_payload[i].req${sep}opt.src.burst = axi_pkg::BURST_INCR; + arb_payload[i].req${sep}opt.dst.burst = axi_pkg::BURST_INCR; // this frontend currently does not support cache variations - arb_dma_req[i]${sep}opt.src.cache = axi_pkg::CACHE_MODIFIABLE; - arb_dma_req[i]${sep}opt.dst.cache = axi_pkg::CACHE_MODIFIABLE; + arb_payload[i].req${sep}opt.src.cache = axi_pkg::CACHE_MODIFIABLE; + arb_payload[i].req${sep}opt.dst.cache = axi_pkg::CACHE_MODIFIABLE; // Backend options - arb_dma_req[i]${sep}opt.beo.decouple_aw = dma_reg2hw[i].conf.decouple_aw.value; - arb_dma_req[i]${sep}opt.beo.decouple_rw = dma_reg2hw[i].conf.decouple_rw.value; - arb_dma_req[i]${sep}opt.beo.src_max_llen = dma_reg2hw[i].conf.src_max_llen.value; - arb_dma_req[i]${sep}opt.beo.dst_max_llen = dma_reg2hw[i].conf.dst_max_llen.value; - arb_dma_req[i]${sep}opt.beo.src_reduce_len = dma_reg2hw[i].conf.src_reduce_len.value; - arb_dma_req[i]${sep}opt.beo.dst_reduce_len = dma_reg2hw[i].conf.dst_reduce_len.value; + arb_payload[i].req${sep}opt.beo.decouple_aw = dma_reg2hw[i].conf.decouple_aw.value; + arb_payload[i].req${sep}opt.beo.decouple_rw = dma_reg2hw[i].conf.decouple_rw.value; + arb_payload[i].req${sep}opt.beo.src_max_llen = dma_reg2hw[i].conf.src_max_llen.value; + arb_payload[i].req${sep}opt.beo.dst_max_llen = dma_reg2hw[i].conf.dst_max_llen.value; + arb_payload[i].req${sep}opt.beo.src_reduce_len = dma_reg2hw[i].conf.src_reduce_len.value; + arb_payload[i].req${sep}opt.beo.dst_reduce_len = dma_reg2hw[i].conf.dst_reduce_len.value; % if num_dim != 1: // ND connections % for nd in range(0, num_dim-1): % if bit_width == '32': - arb_dma_req[i].d_req[${nd}].reps = dma_reg2hw[i].dim[${nd}].reps[0].reps.value; - arb_dma_req[i].d_req[${nd}].src_strides = dma_reg2hw[i].dim[${nd}].src_stride[0].src_stride.value; - arb_dma_req[i].d_req[${nd}].dst_strides = dma_reg2hw[i].dim[${nd}].dst_stride[0].dst_stride.value; + arb_payload[i].req.d_req[${nd}].reps = dma_reg2hw[i].dim[${nd}].reps[0].reps.value; + arb_payload[i].req.d_req[${nd}].src_strides = dma_reg2hw[i].dim[${nd}].src_stride[0].src_stride.value; + arb_payload[i].req.d_req[${nd}].dst_strides = dma_reg2hw[i].dim[${nd}].dst_stride[0].dst_stride.value; % else: - arb_dma_req[i].d_req[${nd}].reps = {dma_reg2hw[i].dim[${nd}].reps[1].reps.value, + arb_payload[i].req.d_req[${nd}].reps = {dma_reg2hw[i].dim[${nd}].reps[1].reps.value, dma_reg2hw[i].dim[${nd}].reps[0].reps.value }; - arb_dma_req[i].d_req[${nd}].src_strides = {dma_reg2hw[i].dim[${nd}].src_stride[1].src_stride.value, + arb_payload[i].req.d_req[${nd}].src_strides = {dma_reg2hw[i].dim[${nd}].src_stride[1].src_stride.value, dma_reg2hw[i].dim[${nd}].src_stride[0].src_stride.value}; - arb_dma_req[i].d_req[${nd}].dst_strides = {dma_reg2hw[i].dim[${nd}].dst_stride[1].dst_stride.value, + arb_payload[i].req.d_req[${nd}].dst_strides = {dma_reg2hw[i].dim[${nd}].dst_stride[1].dst_stride.value, dma_reg2hw[i].dim[${nd}].dst_stride[0].dst_stride.value}; % endif % endfor @@ -242,13 +246,13 @@ module idma_${identifier} #( // Disable higher dimensions if ( dma_reg2hw[i].conf.enable_nd.value == 0) begin % for nd in range(0, num_dim-1): - arb_dma_req[i].d_req[${nd}].reps = ${"'0" if nd != num_dim-2 else "'d1"}; + arb_payload[i].req.d_req[${nd}].reps = ${"'0" if nd != num_dim-2 else "'d1"}; % endfor end % for nd in range(1, num_dim-1): else if ( dma_reg2hw[i].conf.enable_nd.value == ${nd}) begin % for snd in range(nd, num_dim-1): - arb_dma_req[i].d_req[${snd}].reps = 'd1; + arb_payload[i].req.d_req[${snd}].reps = 'd1; % endfor end % endfor @@ -284,7 +288,7 @@ module idma_${identifier} #( // arbitration rr_arb_tree #( .NumIn ( NumRegs ), - .DataType ( dma_req_t ), + .DataType ( arb_payload_t ), .ExtPrio ( 0 ), .AxiVldRdy ( 1 ), .LockIn ( 1 ) @@ -295,10 +299,10 @@ module idma_${identifier} #( .rr_i ( '0 ), .req_i ( arb_valid ), .gnt_o ( arb_ready ), - .data_i ( arb_dma_req ), + .data_i ( arb_payload ), .gnt_i ( req_ready_i ), .req_o ( req_valid_o ), - .data_o ( dma_req_o ), + .data_o ( arb_payload_out ), .idx_o ( /* NC */ ) ); diff --git a/target/sw/.gitignore b/target/sw/.gitignore new file mode 100644 index 00000000..424c745c --- /dev/null +++ b/target/sw/.gitignore @@ -0,0 +1 @@ +*.h diff --git a/util/deploy.py b/util/deploy.py index d004f401..2f2cb82a 100644 --- a/util/deploy.py +++ b/util/deploy.py @@ -7,31 +7,46 @@ # - Thomas Benz """Deploy script run by ci. Creates a deploy branch which includes generated files.""" -import os -import time - -# Git command fragments -GET_BRANCH_CMD = '''git for-each-ref --format='%(objectname) %(refname:short)' refs/heads |\ - awk "/^$(git rev-parse HEAD)/ {print \\$2}"''' -GET_COMMIT_ID_CMD = 'git rev-parse HEAD' -GET_COMMIT_MSG_CMD = 'git log -1 --pretty=%B' -GIT_ADD_ALL_CMD = 'git add .' -GIT_CHECKOUT_TAG_CMD = 'git checkout -b' -GIT_COMMIT_CMD = 'git commit -m' -GIT_PUSH_CMD = 'git push' +import subprocess + # Repo configuration ORIGIN = 'origin' +GITIGNORE_FILES = ['target/rtl/.gitignore', 'target/sw/.gitignore'] # Comment added to gitignore GITIGNORE_COMMENT = '# Deactivated by deploy.py' + +def git_output(*args): + """Run a git command and return its stdout without invoking a shell.""" + return subprocess.check_output(['git', *args], text=True).strip() + + +def git_run(*args): + """Run a git command without invoking a shell.""" + subprocess.run(['git', *args], check=True) + + +def get_current_branch(): + """Return the local branch pointing at HEAD, matching the previous shell pipeline.""" + current_hash = git_output('rev-parse', 'HEAD') + refs = git_output('for-each-ref', '--format=%(objectname) %(refname:short)', 'refs/heads') + + for ref in refs.splitlines(): + object_name, branch_name = ref.split(maxsplit=1) + if object_name == current_hash: + return branch_name + + raise RuntimeError(f'Could not find a local branch pointing at {current_hash}') + + # get current branch info -current_branch = os.popen(GET_BRANCH_CMD).read().split('\n')[0] +current_branch = get_current_branch() print(f'Current branch: {current_branch}') -current_hash = os.popen(GET_COMMIT_ID_CMD).read().split('\n')[0] +current_hash = git_output('rev-parse', 'HEAD') print(f'Current hash: {current_hash}') -current_msg = '\n'.join(os.popen(GET_COMMIT_MSG_CMD).read().split('\n')[:-1]) +current_msg = git_output('log', '-1', '--pretty=%B') print(f'Current commit message: \n{current_msg}') # create target branch @@ -41,24 +56,22 @@ print(f'Deploy commit message:\n{deploy_msg}') # create new deploy branch -os.popen(f'{GIT_CHECKOUT_TAG_CMD} {deploy_branch} {current_branch}') -time.sleep(2) +git_run('checkout', '-b', deploy_branch, current_branch) # selectively deactivate gitignore to check in generated files -with open('target/rtl/.gitignore', 'r', encoding='utf-8') as f: - content = f.read().split('\n')[:-1] +for gitignore_fn in GITIGNORE_FILES: + with open(gitignore_fn, 'r', encoding='utf-8') as f: + content = f.read().split('\n')[:-1] -if content[0] != GITIGNORE_COMMENT: - with open('target/rtl/.gitignore', 'w', encoding='utf-8') as f: - f.write(f'{GITIGNORE_COMMENT}\n') - for line in content: - f.write(f'# {line}\n') + if content[0] != GITIGNORE_COMMENT: + with open(gitignore_fn, 'w', encoding='utf-8') as f: + f.write(f'{GITIGNORE_COMMENT}\n') + for line in content: + f.write(f'# {line}\n') # add and commit files -os.popen(GIT_ADD_ALL_CMD) -time.sleep(0.5) -os.popen(f'{GIT_COMMIT_CMD} "{deploy_msg}"') -time.sleep(0.5) +git_run('add', '.') +git_run('commit', '-m', deploy_msg) # push state to origin -os.popen(f'{GIT_PUSH_CMD} {ORIGIN} {deploy_branch}') +git_run('push', ORIGIN, deploy_branch) diff --git a/uv.lock b/uv.lock index 9b68b293..43c66a9a 100644 --- a/uv.lock +++ b/uv.lock @@ -266,6 +266,7 @@ dependencies = [ { name = "hjson" }, { name = "mako" }, { name = "peakrdl" }, + { name = "peakrdl-cheader" }, { name = "peakrdl-rawheader" }, { name = "pre-commit" }, { name = "pylint" }, @@ -284,6 +285,7 @@ requires-dist = [ { name = "hjson" }, { name = "mako" }, { name = "peakrdl", specifier = ">=1.5.0" }, + { name = "peakrdl-cheader", specifier = ">=1.1.0" }, { name = "peakrdl-rawheader", specifier = ">=0.2.4" }, { name = "pre-commit" }, { name = "pylint" }, @@ -775,23 +777,23 @@ resolution-markers = [ "python_full_version < '3.12'", ] dependencies = [ - { name = "alabaster", marker = "python_full_version < '3.12'" }, - { name = "babel", marker = "python_full_version < '3.12'" }, - { name = "colorama", marker = "python_full_version < '3.12' and sys_platform == 'win32'" }, - { name = "docutils", marker = "python_full_version < '3.12'" }, - { name = "imagesize", marker = "python_full_version < '3.12'" }, - { name = "jinja2", marker = "python_full_version < '3.12'" }, - { name = "packaging", marker = "python_full_version < '3.12'" }, - { name = "pygments", marker = "python_full_version < '3.12'" }, - { name = "requests", marker = "python_full_version < '3.12'" }, - { name = "roman-numerals", marker = "python_full_version < '3.12'" }, - { name = "snowballstemmer", marker = "python_full_version < '3.12'" }, - { name = "sphinxcontrib-applehelp", marker = "python_full_version < '3.12'" }, - { name = "sphinxcontrib-devhelp", marker = "python_full_version < '3.12'" }, - { name = "sphinxcontrib-htmlhelp", marker = "python_full_version < '3.12'" }, - { name = "sphinxcontrib-jsmath", marker = "python_full_version < '3.12'" }, - { name = "sphinxcontrib-qthelp", marker = "python_full_version < '3.12'" }, - { name = "sphinxcontrib-serializinghtml", marker = "python_full_version < '3.12'" }, + { name = "alabaster" }, + { name = "babel" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "docutils" }, + { name = "imagesize" }, + { name = "jinja2" }, + { name = "packaging" }, + { name = "pygments" }, + { name = "requests" }, + { name = "roman-numerals" }, + { name = "snowballstemmer" }, + { name = "sphinxcontrib-applehelp" }, + { name = "sphinxcontrib-devhelp" }, + { name = "sphinxcontrib-htmlhelp" }, + { name = "sphinxcontrib-jsmath" }, + { name = "sphinxcontrib-qthelp" }, + { name = "sphinxcontrib-serializinghtml" }, ] sdist = { url = "https://files.pythonhosted.org/packages/42/50/a8c6ccc36d5eacdfd7913ddccd15a9cee03ecafc5ee2bc40e1f168d85022/sphinx-9.0.4.tar.gz", hash = "sha256:594ef59d042972abbc581d8baa577404abe4e6c3b04ef61bd7fc2acbd51f3fa3", size = 8710502, upload-time = "2025-12-04T07:45:27.343Z" } wheels = [ @@ -806,23 +808,23 @@ resolution-markers = [ "python_full_version >= '3.12'", ] dependencies = [ - { name = "alabaster", marker = "python_full_version >= '3.12'" }, - { name = "babel", marker = "python_full_version >= '3.12'" }, - { name = "colorama", marker = "python_full_version >= '3.12' and sys_platform == 'win32'" }, - { name = "docutils", marker = "python_full_version >= '3.12'" }, - { name = "imagesize", marker = "python_full_version >= '3.12'" }, - { name = "jinja2", marker = "python_full_version >= '3.12'" }, - { name = "packaging", marker = "python_full_version >= '3.12'" }, - { name = "pygments", marker = "python_full_version >= '3.12'" }, - { name = "requests", marker = "python_full_version >= '3.12'" }, - { name = "roman-numerals", marker = "python_full_version >= '3.12'" }, - { name = "snowballstemmer", marker = "python_full_version >= '3.12'" }, - { name = "sphinxcontrib-applehelp", marker = "python_full_version >= '3.12'" }, - { name = "sphinxcontrib-devhelp", marker = "python_full_version >= '3.12'" }, - { name = "sphinxcontrib-htmlhelp", marker = "python_full_version >= '3.12'" }, - { name = "sphinxcontrib-jsmath", marker = "python_full_version >= '3.12'" }, - { name = "sphinxcontrib-qthelp", marker = "python_full_version >= '3.12'" }, - { name = "sphinxcontrib-serializinghtml", marker = "python_full_version >= '3.12'" }, + { name = "alabaster" }, + { name = "babel" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "docutils" }, + { name = "imagesize" }, + { name = "jinja2" }, + { name = "packaging" }, + { name = "pygments" }, + { name = "requests" }, + { name = "roman-numerals" }, + { name = "snowballstemmer" }, + { name = "sphinxcontrib-applehelp" }, + { name = "sphinxcontrib-devhelp" }, + { name = "sphinxcontrib-htmlhelp" }, + { name = "sphinxcontrib-jsmath" }, + { name = "sphinxcontrib-qthelp" }, + { name = "sphinxcontrib-serializinghtml" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cd/bd/f08eb0f4eed5c83f1ba2a3bd18f7745a2b1525fad70660a1c00224ec468a/sphinx-9.1.0.tar.gz", hash = "sha256:7741722357dd75f8190766926071fed3bdc211c74dd2d7d4df5404da95930ddb", size = 8718324, upload-time = "2025-12-31T15:09:27.646Z" } wheels = [