feat: refactor JPEG table register bank and enhance flow script

- Updated the JPEG table register bank module to use combinational logic for data handling and simplified the write logic for quantization, DC, and AC entries.
- Introduced a new function in the run_flow script to handle process termination more gracefully, including signal handling for interrupts.
- Enhanced the flow script to log peak RSS memory usage during execution.
- Modified multiple testbench files to include new storage access signals and improved the test logic for better validation of KWS and SRAM interactions.
- Updated tests to validate the new peak RSS memory logging in the flow script.
- Adjusted Yosys synthesis recipes to include timeout settings and ensure proper reporting of pre-memory synthesis outputs.
This commit is contained in:
maksyuki committed 2026-09-24 07:41:43 +08:00
1 parent fc6440989f
commit 7592808464
17 files changed
+954 -459

No files matched your search

+12
View File
@@ -172,6 +172,18 @@ duration, warning signatures, and netlist simulation verdict together. The
improved metric is not sufficient to replace `balanced`. Metrics policy remains
in `observe` mode while recipe baselines are collected and reviewed.
Every Yosys run writes `yosys-perf.json`, `<top>_pre_memory.rpt`, and
`<top>_pre_memory.json` immediately before memory lowering. These reports are
the authoritative pass-timing and inferred-memory inventory for memories that
would otherwise be expanded into registers and muxes. Structured flow results
also record `peak_rss_kib`, the operating system's maximum resident-set
observation for the child tool. Keep both artifacts when a synthesis run times
out or is interrupted; a missing final netlist is never a successful synthesis
result.
The full and block Yosys flows enforce `YOSYS_TIMEOUT=10800` seconds by
default. Override it only for an explicitly reviewed diagnostic run; timeout
exit 124 remains a failed synthesis verdict.
Generated filelists and MPW output are flow-local. Make depfiles track expanded RTL sources and
included headers. The shared MPW generator is protected by a file lock. Default tool parallelism is
capped at 16 and can be set with `JOBS=<n>` or `MAX_JOBS=<n>`.
+3 -2
View File
@@ -120,7 +120,8 @@ $(APU_BLOCK_NETLIST): $(APU_BLOCK_FL) $(APU_BLOCK_YOSYS_SCRIPTS)
--env PROJ_NAME=$(APU_BLOCK_TOP) --env WORK=$(APU_BLOCK_TMP) \
--env BUILD=$(APU_BLOCK_OUT) --env REPORTS=$(APU_BLOCK_RPT) \
--env NETLIST=$(APU_BLOCK_NETLIST) -- \
yosys -c $(APU_BLOCK_SYNTH_TCL)
timeout --foreground --kill-after=5s $(YOSYS_TIMEOUT)s \
yosys -t --perffile $(APU_BLOCK_SYN)/yosys-perf.json -c $(APU_BLOCK_SYNTH_TCL)
apu-block-synth: $(APU_BLOCK_NETLIST)
@@ -170,4 +171,4 @@ apu-block-clean:
python3 $(ROOT_PATH)/scripts/clean.py --root $(ROOT_PATH) --path $(APU_BLOCK_REPORT_DIR)
.PHONY: apu-block-filelist apu-block-synth apu-block-sta apu-block-report \
apu-block-evidence apu-block-clean
apu-block-evidence apu-block-clean
+3 -2
View File
@@ -83,7 +83,8 @@ $(GA2D_BLOCK_NETLIST): $(GA2D_BLOCK_FLIST) $(GA2D_BLOCK_SCRIPTS)
--env PROJ_NAME=$(GA2D_BLOCK_TOP) --env WORK=$(GA2D_BLOCK_TMP) \
--env BUILD=$(GA2D_BLOCK_OUT) --env REPORTS=$(GA2D_BLOCK_RPT) \
--env NETLIST=$(GA2D_BLOCK_NETLIST) -- \
yosys -c $(YOSYS_DIR)/script/synth.tcl
timeout --foreground --kill-after=5s $(YOSYS_TIMEOUT)s \
yosys -t --perffile $(GA2D_BLOCK_BUILD)/yosys-perf.json -c $(YOSYS_DIR)/script/synth.tcl
# Fails loudly on inferred latches or non-PDK (black-box/unmapped) cells and
# records the register/FIFO mapping summary consumed by the evidence section.
@@ -175,4 +176,4 @@ sta-ga2d-block-clean:
python3 $(ROOT_PATH)/scripts/clean.py --root $(ROOT_PATH) --path $(GA2D_BLOCK_STA_DIR)
.PHONY: synth-ga2d-block synth-ga2d-block-clean netsim-ga2d-block netsim-ga2d-block-clean \
sta-ga2d-block sta-ga2d-block-clean
sta-ga2d-block sta-ga2d-block-clean
@@ -87,6 +87,10 @@ yosys booth
yosys alumacc
yosys share
yosys opt
# Capture the hierarchy and inferred-memory inventory immediately before the
# memory lowering pass. This report survives a later timeout or resource abort.
yosys tee -q -o "${report_dir}/${proj_name}_pre_memory.rpt" stat
yosys tee -q -o "${report_dir}/${proj_name}_pre_memory.json" stat -json
yosys memory
yosys opt -fast
@@ -68,6 +68,10 @@ yosys booth
yosys alumacc
yosys share
yosys opt
# Capture the hierarchy and inferred-memory inventory immediately before the
# memory lowering pass. This report survives a later timeout or resource abort.
yosys tee -q -o "${report_dir}/${proj_name}_pre_memory.rpt" stat
yosys tee -q -o "${report_dir}/${proj_name}_pre_memory.json" stat -json
yosys memory
yosys opt -fast
+4 -2
View File
@@ -24,6 +24,7 @@ YOSYS_BUILD := $(SYN_BUILD_ROOT)
YOSYS_OUT := $(YOSYS_BUILD)/out
YOSYS_TMP := $(YOSYS_BUILD)/tmp
YOSYS_RPT := $(YOSYS_BUILD)/rpt
YOSYS_TIMEOUT ?= 10800
include $(YOSYS_DIR)/synth_config.mk
@@ -69,7 +70,8 @@ $(NETLIST): $(SV_FLIST) $(YOSYS_SCRIPTS)
--env SV_FLIST=$(SV_FLIST) --env TOP_DESIGN=$(TOP_DESIGN) --env CONFIG=$(NETLIST_CONFIG) \
--env PROJ_NAME=$(RTL_NAME) --env WORK=$(YOSYS_TMP) --env BUILD=$(YOSYS_OUT) \
--env REPORTS=$(YOSYS_RPT) --env NETLIST=$(NETLIST) -- \
yosys -c $(YOSYS_DIR)/script/synth.tcl
timeout --foreground --kill-after=5s $(YOSYS_TIMEOUT)s \
yosys -t --perffile $(YOSYS_BUILD)/yosys-perf.json -c $(YOSYS_DIR)/script/synth.tcl
$(NETLIST_DEBUG): $(NETLIST)
@test -f $@
@@ -77,4 +79,4 @@ $(NETLIST_DEBUG): $(NETLIST)
synth_clean:
python3 $(ROOT_PATH)/scripts/clean.py --root $(ROOT_PATH) --path $(YOSYS_BUILD)
.PHONY: gen_synth_filelist synth_clean synth
.PHONY: gen_synth_filelist synth_clean synth
+18
View File
@@ -248,7 +248,11 @@ module apb4_apu #(
logic s_mc_proof_memo_full_unused;
logic [ 31:0] s_kws_sram_data_unused;
logic s_kws_sram_valid_unused, s_kws_sram_err_unused;
logic s_kws_storage_req, s_kws_storage_ready, s_kws_storage_done;
logic s_kws_storage_progress, s_kws_storage_write;
logic [15:0] s_kws_model_read_valid;
logic s_kws_scratch_clear, s_kws_scratch_err;
logic [19:0] s_kws_scratch_read_valid;
logic [19:0][15:0] s_kws_scratch_read_addr;
logic [19:0][31:0] s_kws_scratch_read_data;
logic [ 5:0] s_kws_scratch_write_valid;
@@ -718,9 +722,16 @@ module apb4_apu #(
.memory_input_used_o (s_kws_mem_input_used),
.kws_config_i (s_codec_kws_config_valid ? s_codec_kws_config : s_kws_config),
.input_config_i (s_kws_input_config),
.storage_req_o (s_kws_storage_req),
.storage_ready_i (s_kws_storage_ready),
.storage_done_i (s_kws_storage_done),
.storage_progress_i (s_kws_storage_progress),
.storage_write_o (s_kws_storage_write),
.model_read_valid_o (s_kws_model_read_valid),
.model_addr_o (s_kws_model_read_addr),
.model_data_i (s_kws_model_read_data),
.scratch_clear_o (s_kws_scratch_clear),
.scratch_read_valid_o (s_kws_scratch_read_valid),
.scratch_read_addr_o (s_kws_scratch_read_addr),
.scratch_read_data_i (s_kws_scratch_read_data),
.scratch_write_valid_o (s_kws_scratch_write_valid),
@@ -920,9 +931,16 @@ module apb4_apu #(
.data_o (s_kws_sram_data_unused),
.valid_o (s_kws_sram_valid_unused),
.access_err_o (s_kws_sram_err_unused),
.access_req_i (s_kws_storage_req),
.access_ready_o (s_kws_storage_ready),
.access_done_o (s_kws_storage_done),
.access_progress_o (s_kws_storage_progress),
.access_write_i (s_kws_storage_write),
.model_read_valid_i (s_kws_model_read_valid),
.model_addr_i (s_kws_model_read_addr),
.model_data_o (s_kws_model_read_data),
.scratch_clear_i (s_kws_scratch_clear),
.scratch_read_valid_i (s_kws_scratch_read_valid),
.scratch_read_addr_i (s_kws_scratch_read_addr),
.scratch_read_data_o (s_kws_scratch_read_data),
.scratch_write_valid_i(s_kws_scratch_write_valid),
+344 -273
View File
@@ -49,9 +49,16 @@ module apu_kws_engine (
output logic [31:0] memory_input_used_o,
input logic [15:0] kws_config_i,
input logic [31:0] input_config_i,
output logic storage_req_o,
input logic storage_ready_i,
input logic storage_done_i,
input logic storage_progress_i,
output logic storage_write_o,
output logic [15:0] model_read_valid_o,
output logic [15:0][14:0] model_addr_o,
input logic [15:0][ 7:0] model_data_i,
output logic scratch_clear_o,
output logic [19:0] scratch_read_valid_o,
output logic [19:0][15:0] scratch_read_addr_o,
input logic [19:0][31:0] scratch_read_data_i,
output logic [ 5:0] scratch_write_valid_o,
@@ -175,6 +182,9 @@ module apu_kws_engine (
logic [31:0] s_fault_addr_q, s_fault_detail_q;
logic [31:0] s_front_watchdog_q, s_infer_watchdog_q;
logic s_front_progress, s_infer_progress;
logic s_storage_wait_q, s_storage_write_phase_q, s_storage_state_owned_q;
logic s_storage_read_access, s_storage_write_access, s_storage_has_access;
logic s_storage_final_done, s_storage_state_step;
logic s_config_valid, s_continuous_active, s_listening, s_capture_available;
logic s_stream_accept, s_stream_legal, s_window_deadline, s_mel_overwrite;
@@ -578,8 +588,8 @@ module apu_kws_engine (
!s_stop_latched_q && model_valid_i && model_lock_i && s_config_valid;
assign s_listening = s_continuous_active && s_en_q && !flush_busy_i;
assign s_capture_available = (s_front_state_q == FrontIdle) && !s_frame_pending_q &&
!s_window_pending_q && (s_fir_tap_q == 6'd0);
assign rx_ready_o = s_listening && s_capture_available;
!s_window_pending_q && (s_infer_state_q == InferIdle) && (s_fir_tap_q == 6'd0);
assign rx_ready_o = s_listening && s_capture_available && !s_storage_wait_q && storage_ready_i;
assign s_stream_accept = stream_i.tvalid && rx_ready_o;
assign s_stream_legal = (stream_i.tkeep == 4'hf) && (stream_i.tstrb == 4'hf) && !stream_i.tlast;
assign s_window_deadline = s_commit_valid &&
@@ -754,9 +764,11 @@ module apu_kws_engine (
assign s_mac_total = s_mac_q + s_lane_sum;
always_comb begin
model_addr_o = '0;
scratch_read_addr_o = '0;
s_lane_active = 16'd0;
model_read_valid_o = 16'd0;
model_addr_o = '0;
scratch_read_valid_o = 20'd0;
scratch_read_addr_o = '0;
s_lane_active = 16'd0;
for (int lane = 0; lane < 16; lane++) begin
s_lane_term[lane] = {1'b0, s_term_q} + 9'(lane);
s_lane_input_index[lane] = 13'd0;
@@ -766,14 +778,17 @@ module apu_kws_engine (
end
unique case (s_front_state_q)
FrontFir: begin
scratch_read_valid_o[0] = 1'b1;
scratch_read_addr_o[0] = `RETROSOC_APU_KWS__SCRATCH_FIR_BASE +
{9'd0, fir_history_index(s_fir_write_q, s_fir_tap_q), 1'b0};
end
FrontFftLoad: begin
scratch_read_valid_o[0] = 1'b1;
scratch_read_addr_o[0] = `RETROSOC_APU_KWS__SCRATCH_INGRESS_BASE +
16'(ingress_add(s_frame_start_q, s_front_index_q) * 2);
end
FrontFftRun: begin
scratch_read_valid_o[3:0] = 4'hf;
scratch_read_addr_o[0] =
`RETROSOC_APU_KWS__SCRATCH_FFT_REAL_BASE + 16'(s_fft_left_index * 4);
scratch_read_addr_o[1] =
@@ -784,23 +799,28 @@ module apu_kws_engine (
`RETROSOC_APU_KWS__SCRATCH_FFT_IMAG_BASE + 16'(s_fft_right_index * 4);
end
FrontMagnitude: begin
scratch_read_valid_o[1:0] = 2'b11;
scratch_read_addr_o[0] =
`RETROSOC_APU_KWS__SCRATCH_FFT_REAL_BASE + 16'(s_front_index_q * 4);
scratch_read_addr_o[1] =
`RETROSOC_APU_KWS__SCRATCH_FFT_IMAG_BASE + 16'(s_front_index_q * 4);
end
FrontMel: begin
scratch_read_addr_o[0] = `RETROSOC_APU_KWS__SCRATCH_FFT_REAL_BASE + 16'(s_mel_bin_q * 4);
scratch_read_valid_o[0] = 1'b1;
scratch_read_addr_o[0] = `RETROSOC_APU_KWS__SCRATCH_FFT_REAL_BASE + 16'(s_mel_bin_q * 4);
end
FrontPeak: begin
scratch_read_addr_o[0] = `RETROSOC_APU_KWS__SCRATCH_PEAK_BASE + 16'(s_peak_scan_q * 2);
scratch_read_valid_o[0] = 1'b1;
scratch_read_addr_o[0] = `RETROSOC_APU_KWS__SCRATCH_PEAK_BASE + 16'(s_peak_scan_q * 2);
end
FrontLog: begin
scratch_read_valid_o[0] = 1'b1;
scratch_read_addr_o[0] = `RETROSOC_APU_KWS__SCRATCH_MEL_BASE +
16'((16'(s_log_row_index) * 16'd40 + 16'(s_mfcc_band_q)) * 16'd4);
end
FrontDct: begin
scratch_read_addr_o[0] = `RETROSOC_APU_KWS__SCRATCH_FFT_IMAG_BASE + 16'(s_mfcc_band_q * 4);
scratch_read_valid_o[0] = 1'b1;
scratch_read_addr_o[0] = `RETROSOC_APU_KWS__SCRATCH_FFT_IMAG_BASE + 16'(s_mfcc_band_q * 4);
end
default: begin
end
@@ -808,34 +828,42 @@ module apu_kws_engine (
if (s_infer_state_q == InferPool) begin
for (int lane = 0; lane < 16; lane++) begin
if (({1'b0, s_term_q} + 9'(lane)) < 9'd125) begin
scratch_read_valid_o[lane+4] = 1'b1;
scratch_read_addr_o[lane+4] = `RETROSOC_APU_KWS__SCRATCH_A_BASE +
16'((32'(s_term_q) + 32'(lane)) * 32'd64 + 32'(s_output_q));
end
end
end else if ((s_infer_state_q == InferSoftmaxMax) || (s_infer_state_q == InferSoftmaxSum)) begin
scratch_read_addr_o[4] = `RETROSOC_APU_KWS__SCRATCH_LOGITS_BASE + 16'(s_softmax_index_q);
scratch_read_valid_o[4] = 1'b1;
scratch_read_addr_o[4] = `RETROSOC_APU_KWS__SCRATCH_LOGITS_BASE + 16'(s_softmax_index_q);
end else if ((s_infer_state_q == InferSoftmaxScale) && (s_softmax_index_q > 0)) begin
scratch_read_valid_o[4] = 1'b1;
scratch_read_addr_o[4] =
`RETROSOC_APU_KWS__SCRATCH_LOGITS_BASE + 16'(s_softmax_index_q - 1'b1);
end else if (s_infer_state_q == InferComplete) begin
for (int class_index = 0; class_index < 12; class_index++) begin
scratch_read_valid_o[class_index+4] = 1'b1;
scratch_read_addr_o[class_index+4] =
`RETROSOC_APU_KWS__SCRATCH_SOFTMAX_BASE + 16'(class_index);
end
end
if (s_infer_state_q == InferBias) begin
for (int lane = 0; lane < 4; lane++) begin
model_addr_o[lane] = s_bias_base + 15'(s_output_channel) * 15'd4 + 15'(lane);
model_read_valid_o[lane] = 1'b1;
model_addr_o[lane] = s_bias_base + 15'(s_output_channel) * 15'd4 + 15'(lane);
end
end else if (s_infer_state_q == InferQuant) begin
for (int lane = 0; lane < 4; lane++) begin
model_addr_o[lane] = s_multiplier_base + 15'(s_output_channel) * 15'd4 + 15'(lane);
model_addr_o[lane+4] = s_shift_base + 15'(s_output_channel) * 15'd4 + 15'(lane);
model_read_valid_o[lane] = 1'b1;
model_read_valid_o[lane+4] = 1'b1;
model_addr_o[lane] = s_multiplier_base + 15'(s_output_channel) * 15'd4 + 15'(lane);
model_addr_o[lane+4] = s_shift_base + 15'(s_output_channel) * 15'd4 + 15'(lane);
end
end else if (s_infer_state_q == InferMac) begin
for (int lane = 0; lane < 16; lane++) begin
if (s_lane_term[lane] < {1'b0, s_term_count}) begin
s_lane_active[lane] = 1'b1;
s_lane_active[lane] = 1'b1;
model_read_valid_o[lane] = 1'b1;
if (s_operator_q == 4'd0) begin
s_lane_input_h[lane] = 7'($signed({1'b0, s_output_height_index})) * 7'sd2 +
7'($signed(s_lane_term[lane] / 9'd4)) - 7'sd4;
@@ -844,6 +872,7 @@ module apu_kws_engine (
s_lane_weight_index[lane] = 15'(s_output_channel) * 15'd40 + 15'(s_lane_term[lane]);
if ((s_lane_input_h[lane] >= 0) && (s_lane_input_h[lane] < 7'sd49) &&
(s_lane_input_w[lane] >= 0) && (s_lane_input_w[lane] < 5'sd10)) begin
scratch_read_valid_o[lane+4] = 1'b1;
s_lane_input_index[lane] =
13'(s_lane_input_h[lane]) * 13'd10 + 13'(s_lane_input_w[lane]);
scratch_read_addr_o[lane+4] =
@@ -858,6 +887,7 @@ module apu_kws_engine (
s_lane_weight_index[lane] = 15'(s_lane_term[lane]) * 15'd64 + 15'(s_output_channel);
if ((s_lane_input_h[lane] >= 0) && (s_lane_input_h[lane] < 7'sd25) &&
(s_lane_input_w[lane] >= 0) && (s_lane_input_w[lane] < 5'sd5)) begin
scratch_read_valid_o[lane+4] = 1'b1;
s_lane_input_index[lane] =
(13'(s_lane_input_h[lane]) * 13'd5 + 13'(s_lane_input_w[lane])) *
13'd64 + 13'(s_output_channel);
@@ -865,6 +895,7 @@ module apu_kws_engine (
16'(s_lane_input_index[lane]);
end
end else begin
scratch_read_valid_o[lane+4] = 1'b1;
s_lane_input_index[lane] = (s_operator_q == 4'd10) ?
13'(s_lane_term[lane]) :
(13'(s_output_spatial_index) * 13'd64 + 13'(s_lane_term[lane]));
@@ -1134,6 +1165,42 @@ module apu_kws_engine (
end
end
assign s_storage_read_access = |model_read_valid_o || |scratch_read_valid_o;
assign s_storage_write_access = |scratch_write_valid_o;
assign s_storage_has_access = s_storage_read_access || s_storage_write_access;
assign storage_write_o = s_storage_write_phase_q || !s_storage_read_access;
assign storage_req_o = !s_storage_wait_q && s_storage_has_access;
assign s_storage_final_done = storage_done_i &&
(s_storage_write_phase_q || !s_storage_read_access || !s_storage_write_access);
assign s_storage_state_step = (!s_storage_wait_q && !s_storage_has_access) ||
(s_storage_final_done && s_storage_state_owned_q);
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
s_storage_wait_q <= 1'b0;
s_storage_write_phase_q <= 1'b0;
s_storage_state_owned_q <= 1'b0;
end else if (soft_reset_i || resource_reset_i || abort_i) begin
s_storage_wait_q <= 1'b0;
s_storage_write_phase_q <= 1'b0;
s_storage_state_owned_q <= 1'b0;
end else begin
if (storage_req_o && storage_ready_i) begin
s_storage_wait_q <= 1'b1;
s_storage_state_owned_q <= (s_front_state_q != FrontIdle) || (s_infer_state_q != InferIdle);
end
if (storage_done_i && s_storage_wait_q) begin
s_storage_wait_q <= 1'b0;
if (!s_storage_write_phase_q && s_storage_read_access && s_storage_write_access) begin
s_storage_write_phase_q <= 1'b1;
end else begin
s_storage_write_phase_q <= 1'b0;
s_storage_state_owned_q <= 1'b0;
end
end
end
end
assign memory_dma_request_valid_o = s_mem_req_q;
assign memory_start_ready_o = enable_i && memory_window_i && model_valid_i && model_lock_i &&
!abort_i && !soft_reset_i && !resource_reset_i && !s_mem_job_q &&
@@ -1338,12 +1405,14 @@ module apu_kws_engine (
s_mem_err_detail_q <= 32'd0;
end
end else begin
if (s_front_state_q == FrontIdle || s_front_progress) begin
if (s_front_state_q == FrontIdle || storage_progress_i ||
(s_storage_state_step && s_front_progress)) begin
s_front_watchdog_q <= 32'd0;
end else if (!(&s_front_watchdog_q)) begin
s_front_watchdog_q <= s_front_watchdog_q + 1'b1;
end
if (s_infer_state_q == InferIdle || s_infer_progress) begin
if (s_infer_state_q == InferIdle || storage_progress_i ||
(s_storage_state_step && s_infer_progress)) begin
s_infer_watchdog_q <= 32'd0;
end else if (!(&s_infer_watchdog_q)) begin
s_infer_watchdog_q <= s_infer_watchdog_q + 1'b1;
@@ -1493,7 +1562,7 @@ module apu_kws_engine (
s_s24_pending_q <= 1'b0;
end
if (s_commit_valid) begin
if (s_commit_valid && ((s_front_state_q == FrontIdle) || s_storage_state_step)) begin
s_ingress_write_q <= s_next_write;
s_epoch_samples_q <= s_next_samples;
s_timestamp_q <= s_timestamp_q + 1'b1;
@@ -1528,295 +1597,297 @@ module apu_kws_engine (
end
end
unique case (s_front_state_q)
FrontIdle: begin
if (s_frame_pending_q) begin
s_frame_pending_q <= 1'b0;
s_front_index_q <= 10'd0;
s_front_state_q <= FrontFftLoad;
end else if (s_window_pending_q && (s_mel_count_q >= 6'd49) &&
if (s_storage_state_step) begin
unique case (s_front_state_q)
FrontIdle: begin
if (s_frame_pending_q) begin
s_frame_pending_q <= 1'b0;
s_front_index_q <= 10'd0;
s_front_state_q <= FrontFftLoad;
end else if (s_window_pending_q && (s_mel_count_q >= 6'd49) &&
(s_infer_state_q == InferIdle)) begin
s_window_pending_q <= 1'b0;
s_peak_scan_q <= 7'd0;
s_window_peak_q <= 16'd1;
s_front_state_q <= FrontPeak;
end
end
FrontFir: begin
if (s_fir_tap_q == 6'd62) begin
s_fir_tap_q <= 6'd0;
s_fir_acc_q <= 64'sd0;
s_fir_phase_q <= (s_fir_phase_q == (s_decimation - 1'b1)) ?
3'd0 : s_fir_phase_q + 1'b1;
s_front_state_q <= FrontIdle;
end else begin
s_fir_acc_q <= s_fir_total;
s_fir_tap_q <= s_fir_tap_q + 1'b1;
end
end
FrontFftLoad: begin
if (s_front_index_q == 10'd511) begin
s_fft_len_q <= 10'd2;
s_fft_half_q <= 9'd1;
s_fft_group_q <= 9'd0;
s_fft_j_q <= 8'd0;
s_front_state_q <= FrontFftRun;
end else begin
s_front_index_q <= s_front_index_q + 1'b1;
end
end
FrontFftRun: begin
if (s_fft_overflow) begin
s_fault_q <= 1'b1;
s_fault_code_q <= `APB4_APU__ERROR_CODE_KWS_ARITHMETIC;
s_fault_stage_q <= `APB4_APU__ERROR_STAGE_KWS_FRONTEND;
s_fault_detail_q <= 32'h0700_0014;
s_stop_latched_q <= 1'b1;
s_front_state_q <= FrontIdle;
end else begin
if (s_fft_j_q + 1'b1 == s_fft_half_q) begin
s_fft_j_q <= 8'd0;
if (s_fft_group_q + s_fft_len_q == 10'd512) begin
s_fft_group_q <= 9'd0;
if (s_fft_len_q == 10'd512) begin
s_front_index_q <= 10'd0;
s_front_state_q <= FrontMagnitude;
end else begin
s_fft_len_q <= s_fft_len_q << 1;
s_fft_half_q <= s_fft_half_q << 1;
end
end else begin
s_fft_group_q <= 9'(s_fft_group_q + s_fft_len_q);
end
end else begin
s_fft_j_q <= s_fft_j_q + 1'b1;
s_window_pending_q <= 1'b0;
s_peak_scan_q <= 7'd0;
s_window_peak_q <= 16'd1;
s_front_state_q <= FrontPeak;
end
end
end
FrontMagnitude: begin
if (s_front_index_q == 10'd256) begin
s_mel_band_q <= 8'd0;
s_mel_bin_q <= 9'd0;
s_mel_acc_q <= 64'd0;
s_front_state_q <= FrontMel;
end else begin
s_front_index_q <= s_front_index_q + 1'b1;
end
end
FrontMel: begin
if (s_mel_total < s_mel_acc_q) begin
s_fault_q <= 1'b1;
s_fault_code_q <= `APB4_APU__ERROR_CODE_KWS_ARITHMETIC;
s_fault_stage_q <= `APB4_APU__ERROR_STAGE_KWS_FRONTEND;
s_fault_detail_q <= 32'h0700_0015;
s_stop_latched_q <= 1'b1;
s_front_state_q <= FrontIdle;
end else if (s_mel_overwrite) begin
s_front_state_q <= FrontIdle;
end else if (s_mel_bin_q == 9'd256) begin
s_mel_bin_q <= 9'd0;
s_mel_acc_q <= 64'd0;
if (s_mel_band_q == 8'd39) begin
s_mel_band_q <= 8'd0;
s_mel_write_q <= (s_mel_write_q == 6'd49) ? 6'd0 : s_mel_write_q + 1'b1;
if (s_mel_count_q < 6'd50) s_mel_count_q <= s_mel_count_q + 1'b1;
if (!counter_clear_i) begin
s_frame_count_q <= (s_frame_count_q == 32'hffff_ffff) ?
s_frame_count_q : s_frame_count_q + 1'b1;
end
FrontFir: begin
if (s_fir_tap_q == 6'd62) begin
s_fir_tap_q <= 6'd0;
s_fir_acc_q <= 64'sd0;
s_fir_phase_q <= (s_fir_phase_q == (s_decimation - 1'b1)) ?
3'd0 : s_fir_phase_q + 1'b1;
s_front_state_q <= FrontIdle;
end else begin
s_mel_band_q <= s_mel_band_q + 1'b1;
s_fir_acc_q <= s_fir_total;
s_fir_tap_q <= s_fir_tap_q + 1'b1;
end
end else begin
s_mel_acc_q <= s_mel_total;
s_mel_bin_q <= s_mel_bin_q + 1'b1;
end
end
FrontPeak: begin
if (s_peak_data > s_window_peak_q) begin
s_window_peak_q <= s_peak_data;
FrontFftLoad: begin
if (s_front_index_q == 10'd511) begin
s_fft_len_q <= 10'd2;
s_fft_half_q <= 9'd1;
s_fft_group_q <= 9'd0;
s_fft_j_q <= 8'd0;
s_front_state_q <= FrontFftRun;
end else begin
s_front_index_q <= s_front_index_q + 1'b1;
end
end
if (s_peak_scan_q == 7'd99) begin
s_mfcc_row_q <= 6'd0;
s_mfcc_band_q <= 6'd0;
s_front_state_q <= FrontLog;
end else begin
s_peak_scan_q <= s_peak_scan_q + 1'b1;
FrontFftRun: begin
if (s_fft_overflow) begin
s_fault_q <= 1'b1;
s_fault_code_q <= `APB4_APU__ERROR_CODE_KWS_ARITHMETIC;
s_fault_stage_q <= `APB4_APU__ERROR_STAGE_KWS_FRONTEND;
s_fault_detail_q <= 32'h0700_0014;
s_stop_latched_q <= 1'b1;
s_front_state_q <= FrontIdle;
end else begin
if (s_fft_j_q + 1'b1 == s_fft_half_q) begin
s_fft_j_q <= 8'd0;
if (s_fft_group_q + s_fft_len_q == 10'd512) begin
s_fft_group_q <= 9'd0;
if (s_fft_len_q == 10'd512) begin
s_front_index_q <= 10'd0;
s_front_state_q <= FrontMagnitude;
end else begin
s_fft_len_q <= s_fft_len_q << 1;
s_fft_half_q <= s_fft_half_q << 1;
end
end else begin
s_fft_group_q <= 9'(s_fft_group_q + s_fft_len_q);
end
end else begin
s_fft_j_q <= s_fft_j_q + 1'b1;
end
end
end
end
FrontLog: begin
if (s_mfcc_band_q == 6'd39) begin
s_mfcc_band_q <= 6'd0;
s_mfcc_coefficient_q <= 4'd0;
s_dct_acc_q <= 64'sd0;
s_front_state_q <= FrontDct;
end else begin
s_mfcc_band_q <= s_mfcc_band_q + 1'b1;
FrontMagnitude: begin
if (s_front_index_q == 10'd256) begin
s_mel_band_q <= 8'd0;
s_mel_bin_q <= 9'd0;
s_mel_acc_q <= 64'd0;
s_front_state_q <= FrontMel;
end else begin
s_front_index_q <= s_front_index_q + 1'b1;
end
end
end
FrontDct: begin
if (s_mfcc_band_q == 6'd39) begin
s_mfcc_band_q <= 6'd0;
s_dct_acc_q <= 64'sd0;
if (s_mfcc_coefficient_q == 4'd9) begin
s_mfcc_coefficient_q <= 4'd0;
if (s_mfcc_row_q == 6'd48) begin
s_operator_q <= 4'd0;
s_output_q <= 14'd0;
s_infer_state_q <= InferBias;
FrontMel: begin
if (s_mel_total < s_mel_acc_q) begin
s_fault_q <= 1'b1;
s_fault_code_q <= `APB4_APU__ERROR_CODE_KWS_ARITHMETIC;
s_fault_stage_q <= `APB4_APU__ERROR_STAGE_KWS_FRONTEND;
s_fault_detail_q <= 32'h0700_0015;
s_stop_latched_q <= 1'b1;
s_front_state_q <= FrontIdle;
end else if (s_mel_overwrite) begin
s_front_state_q <= FrontIdle;
end else if (s_mel_bin_q == 9'd256) begin
s_mel_bin_q <= 9'd0;
s_mel_acc_q <= 64'd0;
if (s_mel_band_q == 8'd39) begin
s_mel_band_q <= 8'd0;
s_mel_write_q <= (s_mel_write_q == 6'd49) ? 6'd0 : s_mel_write_q + 1'b1;
if (s_mel_count_q < 6'd50) s_mel_count_q <= s_mel_count_q + 1'b1;
if (!counter_clear_i) begin
s_frame_count_q <= (s_frame_count_q == 32'hffff_ffff) ?
s_frame_count_q : s_frame_count_q + 1'b1;
end
s_front_state_q <= FrontIdle;
end else begin
s_mfcc_row_q <= s_mfcc_row_q + 1'b1;
s_front_state_q <= FrontLog;
s_mel_band_q <= s_mel_band_q + 1'b1;
end
end else begin
s_mfcc_coefficient_q <= s_mfcc_coefficient_q + 1'b1;
s_mel_acc_q <= s_mel_total;
s_mel_bin_q <= s_mel_bin_q + 1'b1;
end
end else begin
s_dct_acc_q <= s_dct_total;
s_mfcc_band_q <= s_mfcc_band_q + 1'b1;
end
end
default: s_front_state_q <= FrontIdle;
endcase
unique case (s_infer_state_q)
InferIdle: begin
end
InferBias: begin
s_mac_q <= 64'($signed(s_bias_word));
s_term_q <= 8'd0;
s_infer_state_q <= InferMac;
end
InferMac: begin
if ((s_mac_total > 64'sh0000_0000_7fff_ffff) ||
(s_mac_total < -64'sh0000_0000_8000_0000)) begin
s_fault_q <= 1'b1;
s_fault_code_q <= `APB4_APU__ERROR_CODE_KWS_ARITHMETIC;
s_fault_stage_q <= `APB4_APU__ERROR_STAGE_KWS_INFERENCE;
s_fault_detail_q <= 32'h0700_0016;
s_stop_latched_q <= 1'b1;
s_infer_state_q <= InferIdle;
end else if (s_term_q + 8'd16 >= s_term_count) begin
s_mac_q <= s_mac_total;
s_infer_state_q <= InferQuant;
end else begin
s_mac_q <= s_mac_total;
s_term_q <= s_term_q + 8'd16;
FrontPeak: begin
if (s_peak_data > s_window_peak_q) begin
s_window_peak_q <= s_peak_data;
end
if (s_peak_scan_q == 7'd99) begin
s_mfcc_row_q <= 6'd0;
s_mfcc_band_q <= 6'd0;
s_front_state_q <= FrontLog;
end else begin
s_peak_scan_q <= s_peak_scan_q + 1'b1;
end
end
end
InferQuant: begin
if (s_requant_overflow) begin
s_fault_q <= 1'b1;
s_fault_code_q <= `APB4_APU__ERROR_CODE_KWS_ARITHMETIC;
s_fault_stage_q <= `APB4_APU__ERROR_STAGE_KWS_INFERENCE;
s_fault_detail_q <= 32'h0700_0017;
s_stop_latched_q <= 1'b1;
s_infer_state_q <= InferIdle;
end else begin
if (s_output_q + 1'b1 == s_output_count) begin
s_output_q <= 14'd0;
if (s_operator_q == 4'd8) begin
s_operator_q <= 4'd9;
s_term_q <= 8'd0;
s_mac_q <= 64'sd0;
s_infer_state_q <= InferPool;
end else if (s_operator_q == 4'd10) begin
s_operator_q <= 4'd11;
s_softmax_index_q <= 4'd0;
s_softmax_max_q <= -8'sd128;
s_infer_state_q <= InferSoftmaxMax;
FrontLog: begin
if (s_mfcc_band_q == 6'd39) begin
s_mfcc_band_q <= 6'd0;
s_mfcc_coefficient_q <= 4'd0;
s_dct_acc_q <= 64'sd0;
s_front_state_q <= FrontDct;
end else begin
s_mfcc_band_q <= s_mfcc_band_q + 1'b1;
end
end
FrontDct: begin
if (s_mfcc_band_q == 6'd39) begin
s_mfcc_band_q <= 6'd0;
s_dct_acc_q <= 64'sd0;
if (s_mfcc_coefficient_q == 4'd9) begin
s_mfcc_coefficient_q <= 4'd0;
if (s_mfcc_row_q == 6'd48) begin
s_operator_q <= 4'd0;
s_output_q <= 14'd0;
s_infer_state_q <= InferBias;
s_front_state_q <= FrontIdle;
end else begin
s_mfcc_row_q <= s_mfcc_row_q + 1'b1;
s_front_state_q <= FrontLog;
end
end else begin
s_operator_q <= s_operator_q + 1'b1;
s_mfcc_coefficient_q <= s_mfcc_coefficient_q + 1'b1;
end
end else begin
s_dct_acc_q <= s_dct_total;
s_mfcc_band_q <= s_mfcc_band_q + 1'b1;
end
end
default: s_front_state_q <= FrontIdle;
endcase
unique case (s_infer_state_q)
InferIdle: begin
end
InferBias: begin
s_mac_q <= 64'($signed(s_bias_word));
s_term_q <= 8'd0;
s_infer_state_q <= InferMac;
end
InferMac: begin
if ((s_mac_total > 64'sh0000_0000_7fff_ffff) ||
(s_mac_total < -64'sh0000_0000_8000_0000)) begin
s_fault_q <= 1'b1;
s_fault_code_q <= `APB4_APU__ERROR_CODE_KWS_ARITHMETIC;
s_fault_stage_q <= `APB4_APU__ERROR_STAGE_KWS_INFERENCE;
s_fault_detail_q <= 32'h0700_0016;
s_stop_latched_q <= 1'b1;
s_infer_state_q <= InferIdle;
end else if (s_term_q + 8'd16 >= s_term_count) begin
s_mac_q <= s_mac_total;
s_infer_state_q <= InferQuant;
end else begin
s_mac_q <= s_mac_total;
s_term_q <= s_term_q + 8'd16;
end
end
InferQuant: begin
if (s_requant_overflow) begin
s_fault_q <= 1'b1;
s_fault_code_q <= `APB4_APU__ERROR_CODE_KWS_ARITHMETIC;
s_fault_stage_q <= `APB4_APU__ERROR_STAGE_KWS_INFERENCE;
s_fault_detail_q <= 32'h0700_0017;
s_stop_latched_q <= 1'b1;
s_infer_state_q <= InferIdle;
end else begin
if (s_output_q + 1'b1 == s_output_count) begin
s_output_q <= 14'd0;
if (s_operator_q == 4'd8) begin
s_operator_q <= 4'd9;
s_term_q <= 8'd0;
s_mac_q <= 64'sd0;
s_infer_state_q <= InferPool;
end else if (s_operator_q == 4'd10) begin
s_operator_q <= 4'd11;
s_softmax_index_q <= 4'd0;
s_softmax_max_q <= -8'sd128;
s_infer_state_q <= InferSoftmaxMax;
end else begin
s_operator_q <= s_operator_q + 1'b1;
s_infer_state_q <= InferBias;
end
end else begin
s_output_q <= s_output_q + 1'b1;
s_infer_state_q <= InferBias;
end
end else begin
s_output_q <= s_output_q + 1'b1;
s_infer_state_q <= InferBias;
end
end
end
InferPool: begin
if (s_term_q + 8'd16 >= 8'd125) begin
s_term_q <= 8'd0;
s_mac_q <= 64'sd0;
if (s_output_q == 14'd63) begin
s_output_q <= 14'd0;
s_operator_q <= 4'd10;
s_infer_state_q <= InferBias;
InferPool: begin
if (s_term_q + 8'd16 >= 8'd125) begin
s_term_q <= 8'd0;
s_mac_q <= 64'sd0;
if (s_output_q == 14'd63) begin
s_output_q <= 14'd0;
s_operator_q <= 4'd10;
s_infer_state_q <= InferBias;
end else begin
s_output_q <= s_output_q + 1'b1;
end
end else begin
s_output_q <= s_output_q + 1'b1;
s_mac_q <= s_pool_sum;
s_term_q <= s_term_q + 8'd16;
end
end else begin
s_mac_q <= s_pool_sum;
s_term_q <= s_term_q + 8'd16;
end
end
InferSoftmaxMax: begin
if (s_logit_data > s_softmax_max_q) begin
s_softmax_max_q <= s_logit_data;
InferSoftmaxMax: begin
if (s_logit_data > s_softmax_max_q) begin
s_softmax_max_q <= s_logit_data;
end
if (s_softmax_index_q == 4'd11) begin
s_softmax_index_q <= 4'd0;
s_softmax_sum_q <= 32'd0;
s_infer_state_q <= InferSoftmaxSum;
end else begin
s_softmax_index_q <= s_softmax_index_q + 1'b1;
end
end
if (s_softmax_index_q == 4'd11) begin
s_softmax_index_q <= 4'd0;
s_softmax_sum_q <= 32'd0;
s_infer_state_q <= InferSoftmaxSum;
end else begin
s_softmax_index_q <= s_softmax_index_q + 1'b1;
InferSoftmaxSum: begin
if (s_softmax_sum_diff >= -9'sd124) begin
s_softmax_sum_q <= s_softmax_sum_q +
rounding_divide_pot(apu_kws_softmax_exp_q31(-s_softmax_sum_diff[6:0]), 12);
end
if (s_softmax_index_q == 4'd11) begin
s_softmax_index_q <= 4'd0;
s_infer_state_q <= InferSoftmaxScale;
end else begin
s_softmax_index_q <= s_softmax_index_q + 1'b1;
end
end
end
InferSoftmaxSum: begin
if (s_softmax_sum_diff >= -9'sd124) begin
s_softmax_sum_q <= s_softmax_sum_q +
rounding_divide_pot(apu_kws_softmax_exp_q31(-s_softmax_sum_diff[6:0]), 12);
InferSoftmaxScale: begin
if (s_softmax_index_q == 0) begin
s_softmax_scale_q <= reciprocal_q31(s_softmax_shifted_sum);
s_softmax_bits_q <= 6'(7'sd12 - $signed({1'b0, s_softmax_headroom}));
end
if (s_softmax_index_q == 4'd12) begin
s_softmax_index_q <= 4'd0;
s_infer_state_q <= InferComplete;
end else begin
s_softmax_index_q <= s_softmax_index_q + 1'b1;
end
end
if (s_softmax_index_q == 4'd11) begin
s_softmax_index_q <= 4'd0;
s_infer_state_q <= InferSoftmaxScale;
end else begin
s_softmax_index_q <= s_softmax_index_q + 1'b1;
end
end
InferSoftmaxScale: begin
if (s_softmax_index_q == 0) begin
s_softmax_scale_q <= reciprocal_q31(s_softmax_shifted_sum);
s_softmax_bits_q <= 6'(7'sd12 - $signed({1'b0, s_softmax_headroom}));
end
if (s_softmax_index_q == 4'd12) begin
s_softmax_index_q <= 4'd0;
s_infer_state_q <= InferComplete;
end else begin
s_softmax_index_q <= s_softmax_index_q + 1'b1;
end
end
InferComplete: begin
s_result_q <= {15'd0, s_stable_hit, s_best_score, s_best_class};
s_result_valid_q <= 1'b1;
s_timestamp_lo_q <= s_timestamp_q;
s_timestamp_hi_q <= 32'd0;
if (!counter_clear_i) begin
s_inference_count_q <= (s_inference_count_q == 32'hffff_ffff) ?
s_inference_count_q : s_inference_count_q + 1'b1;
end
s_debounce_run_q <= s_next_debounce_run[7:0];
s_last_class_q <= s_best_class;
s_last_match_q <= s_match;
s_stable_hit_q <= s_stable_hit;
if (s_hit_event) begin
InferComplete: begin
s_result_q <= {15'd0, s_stable_hit, s_best_score, s_best_class};
s_result_valid_q <= 1'b1;
s_timestamp_lo_q <= s_timestamp_q;
s_timestamp_hi_q <= 32'd0;
if (!counter_clear_i) begin
s_hit_count_q <= (s_hit_count_q == 32'hffff_ffff) ?
s_inference_count_q <= (s_inference_count_q == 32'hffff_ffff) ?
s_inference_count_q : s_inference_count_q + 1'b1;
end
s_debounce_run_q <= s_next_debounce_run[7:0];
s_last_class_q <= s_best_class;
s_last_match_q <= s_match;
s_stable_hit_q <= s_stable_hit;
if (s_hit_event) begin
if (!counter_clear_i) begin
s_hit_count_q <= (s_hit_count_q == 32'hffff_ffff) ?
s_hit_count_q : s_hit_count_q + 1'b1;
end
s_hit_irq_q <= 1'b1;
end
s_infer_state_q <= InferIdle;
if (s_mem_job_q) begin
s_mem_job_q <= 1'b0;
s_mem_done_q <= 1'b1;
end
s_hit_irq_q <= 1'b1;
end
s_infer_state_q <= InferIdle;
if (s_mem_job_q) begin
s_mem_job_q <= 1'b0;
s_mem_done_q <= 1'b1;
end
end
default: s_infer_state_q <= InferIdle;
endcase
default: s_infer_state_q <= InferIdle;
endcase
end
if ((s_mem_job_q && s_mem_dma_done_q && !s_mem_word_valid_q) &&
((s_mem_received_q != 32'd32000) || s_mem_err_q)) begin
+309 -82
View File
@@ -16,9 +16,16 @@ module apu_kws_sram_client (
output logic [31:0] data_o,
output logic valid_o,
output logic access_err_o,
input logic access_req_i,
output logic access_ready_o,
output logic access_done_o,
output logic access_progress_o,
input logic access_write_i,
input logic [15:0] model_read_valid_i,
input logic [15:0][14:0] model_addr_i,
output logic [15:0][ 7:0] model_data_o,
input logic scratch_clear_i,
input logic [19:0] scratch_read_valid_i,
input logic [19:0][15:0] scratch_read_addr_i,
output logic [19:0][31:0] scratch_read_data_o,
input logic [ 5:0] scratch_write_valid_i,
@@ -28,108 +35,328 @@ module apu_kws_sram_client (
output logic scratch_access_err_o
// verilog_format: on
);
localparam int unsigned ModelWordCount = `RETROSOC_APU_KWS__MODEL_BYTES / 4;
localparam int unsigned ScratchWordCount = `RETROSOC_APU_KWS__SCRATCH_BYTES / 4;
localparam int unsigned KwsWordCount = ModelWordCount + ScratchWordCount;
localparam int unsigned BankCount = 16;
localparam int unsigned FirEntryCount = 63;
logic [ 31:0] mem [0:KwsWordCount-1];
logic [FirEntryCount-1:0] s_fir_valid_q;
logic s_pending_q;
logic s_err_q;
logic [ 31:0] s_data_q;
logic s_range_ok;
logic [ 13:0] s_word_addr;
logic [ BankCount-1:0] s_bank_cs;
logic [ BankCount-1:0] s_bank_wren;
logic [ BankCount-1:0][ 9:0] s_bank_addr;
logic [ BankCount-1:0][31:0] s_bank_wdata;
logic [ BankCount-1:0][ 3:0] s_bank_wmask;
logic [ BankCount-1:0][31:0] s_bank_rdata;
assign s_range_ok = (addr_i[1:0] == 2'd0) &&
logic s_busy_q;
logic [ 15:0] s_model_pending_q;
logic [ 15:0][14:0] s_model_addr_q;
logic [ 19:0] s_scratch_read_pending_q;
logic [ 19:0][15:0] s_scratch_read_addr_q;
logic [ 5:0] s_scratch_write_pending_q;
logic [ 5:0][15:0] s_scratch_write_addr_q;
logic [ 5:0][31:0] s_scratch_write_data_q;
logic [ 5:0][ 3:0] s_scratch_write_strb_q;
logic [ BankCount-1:0] s_read_pipe_valid_q;
logic [ BankCount-1:0][15:0] s_read_pipe_model_q;
logic [ BankCount-1:0][19:0] s_read_pipe_scratch_q;
logic [ BankCount-1:0] s_issue_write;
logic [ BankCount-1:0][ 2:0] s_issue_write_lane;
logic [ BankCount-1:0] s_issue_read;
logic [ BankCount-1:0][15:0] s_issue_model_mask;
logic [ BankCount-1:0][19:0] s_issue_scratch_mask;
logic [FirEntryCount-1:0] s_fir_valid_q;
logic s_loader_range_ok;
logic [ 14:0] s_loader_offset;
logic [ 3:0] s_loader_bank;
logic [ 9:0] s_loader_row;
logic s_loader_read_pending_q;
logic [ 3:0] s_loader_read_bank_q;
logic s_loader_read_err_q;
`ifndef SYNTHESIS
// Kept as a simulation-loading boundary for the existing APUM/MFCC fixtures.
// The synthesizable macro path below contains only the sixteen physical banks.
logic [31:0] mem[0:16383];
`endif
function automatic logic [3:0] model_bank(input logic [14:0] address_i);
model_bank = {1'b0, address_i[4:2] ^ address_i[8:6]};
endfunction
function automatic logic [3:0] scratch_bank(input logic [15:0] address_i);
scratch_bank = {1'b1, address_i[4:2] ^ address_i[8:6]};
endfunction
function automatic logic [13:0] bank_word(input logic [3:0] bank_i, input logic [9:0] row_i);
bank_word = {bank_i[3], row_i, bank_i[2:0] ^ row_i[3:1]};
endfunction
assign s_loader_range_ok = (addr_i[1:0] == 2'd0) &&
(addr_i >= `APB4_APU__LOCAL_KWS_BASE) &&
(addr_i < (`APB4_APU__LOCAL_KWS_BASE + `RETROSOC_APU_KWS__MODEL_BYTES));
assign s_word_addr = 14'(addr_i[15:2] - 14'h2800);
assign ready_o = rst_n_i && !s_pending_q;
assign data_o = s_data_q;
assign valid_o = s_pending_q && !s_err_q;
assign access_err_o = (req_i && ready_o && !s_range_ok) || (s_pending_q && s_err_q);
assign s_loader_offset = 15'(addr_i - `APB4_APU__LOCAL_KWS_BASE);
assign s_loader_bank = model_bank(s_loader_offset);
assign s_loader_row = s_loader_offset[14:5];
for (genvar lane = 0; lane < 16; lane++) begin : gen_model_read
assign model_data_o[lane] = mem[{1'b0, model_addr_i[lane][14:2]}][8*model_addr_i[lane][1:0]+:8];
end
for (genvar lane = 0; lane < 20; lane++) begin : gen_scratch_read
logic s_fir_range;
logic [ 5:0] s_fir_index;
logic [13:0] s_memory_word;
assign s_fir_range =
(scratch_read_addr_i[lane] >= `RETROSOC_APU_KWS__SCRATCH_FIR_BASE) &&
(scratch_read_addr_i[lane] <
(`RETROSOC_APU_KWS__SCRATCH_FIR_BASE + 16'(FirEntryCount * 2)));
assign s_fir_index = 6'((scratch_read_addr_i[lane] - `RETROSOC_APU_KWS__SCRATCH_FIR_BASE) >> 1);
assign s_memory_word = 14'(ModelWordCount) + {1'b0, scratch_read_addr_i[lane][14:2]};
assign scratch_read_data_o[lane] =
scratch_read_addr_i[lane][15] || (s_fir_range && !s_fir_valid_q[s_fir_index]) ?
32'd0 : mem[s_memory_word];
end
assign ready_o = rst_n_i && !s_busy_q && !s_loader_read_pending_q;
assign data_o = s_bank_rdata[s_loader_read_bank_q];
assign valid_o = s_loader_read_pending_q && !s_loader_read_err_q;
assign access_err_o = (req_i && ready_o && !s_loader_range_ok) ||
(s_loader_read_pending_q && s_loader_read_err_q);
assign access_ready_o = rst_n_i && !s_busy_q && !s_loader_read_pending_q;
assign access_done_o = s_busy_q && (s_model_pending_q == 16'd0) &&
(s_scratch_read_pending_q == 20'd0) && (s_scratch_write_pending_q == 6'd0) &&
(s_read_pipe_valid_q == BankCount'(0));
assign access_progress_o = |s_issue_write || |s_issue_read;
always_comb begin
scratch_access_err_o = 1'b0;
for (int lane = 0; lane < 20; lane++) begin
scratch_access_err_o |= scratch_read_valid_i[lane] && scratch_read_addr_i[lane][15];
end
for (int lane = 0; lane < 6; lane++) begin
scratch_access_err_o |= scratch_write_valid_i[lane] && scratch_write_addr_i[lane][15];
end
end
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
s_fir_valid_q <= FirEntryCount'(0);
s_pending_q <= 1'b0;
s_err_q <= 1'b0;
s_data_q <= 32'd0;
end else begin
s_pending_q <= 1'b0;
s_err_q <= 1'b0;
if (scratch_clear_i) begin
s_fir_valid_q <= FirEntryCount'(0);
end
if (req_i && ready_o) begin
if (!s_range_ok) begin
s_pending_q <= 1'b1;
s_err_q <= 1'b1;
end else if (write_i) begin
if (strb_i[0]) mem[s_word_addr][7:0] <= data_i[7:0];
if (strb_i[1]) mem[s_word_addr][15:8] <= data_i[15:8];
if (strb_i[2]) mem[s_word_addr][23:16] <= data_i[23:16];
if (strb_i[3]) mem[s_word_addr][31:24] <= data_i[31:24];
end else begin
s_data_q <= mem[s_word_addr];
s_pending_q <= 1'b1;
always_comb begin
s_bank_cs = BankCount'(0);
s_bank_wren = BankCount'(0);
s_bank_addr = '0;
s_bank_wdata = '0;
s_bank_wmask = '0;
s_issue_write = BankCount'(0);
s_issue_write_lane = '0;
s_issue_read = BankCount'(0);
s_issue_model_mask = '0;
s_issue_scratch_mask = '0;
if (req_i && ready_o && s_loader_range_ok) begin
s_bank_cs[s_loader_bank] = 1'b1;
s_bank_wren[s_loader_bank] = write_i;
s_bank_addr[s_loader_bank] = s_loader_row;
s_bank_wdata[s_loader_bank] = data_i;
s_bank_wmask[s_loader_bank] = strb_i;
end else if (s_busy_q) begin
for (int bank = 0; bank < BankCount; bank++) begin
for (int lane = 0; lane < 6; lane++) begin
if (!s_bank_cs[bank] && s_scratch_write_pending_q[lane] && (scratch_bank(
s_scratch_write_addr_q[lane]
) == 4'(bank))) begin
s_issue_write[bank] = 1'b1;
s_issue_write_lane[bank] = 3'(lane);
s_bank_cs[bank] = 1'b1;
s_bank_wren[bank] = 1'b1;
s_bank_addr[bank] = s_scratch_write_addr_q[lane][14:5];
s_bank_wdata[bank] = s_scratch_write_data_q[lane];
s_bank_wmask[bank] = s_scratch_write_strb_q[lane];
end
end
for (int lane = 0; lane < 20; lane++) begin
if (!s_bank_cs[bank] && s_scratch_read_pending_q[lane] && (scratch_bank(
s_scratch_read_addr_q[lane]
) == 4'(bank))) begin
s_issue_read[bank] = 1'b1;
s_bank_cs[bank] = 1'b1;
s_bank_addr[bank] = s_scratch_read_addr_q[lane][14:5];
end
end
for (int lane = 0; lane < 16; lane++) begin
if (!s_bank_cs[bank] && s_model_pending_q[lane] && (model_bank(
s_model_addr_q[lane]
) == 4'(bank))) begin
s_issue_read[bank] = 1'b1;
s_bank_cs[bank] = 1'b1;
s_bank_addr[bank] = s_model_addr_q[lane][14:5];
end
end
end
for (int lane = 0; lane < 6; lane++) begin
if (scratch_write_valid_i[lane] && !scratch_write_addr_i[lane][15]) begin
if (scratch_write_strb_i[lane][0]) begin
mem[14'(ModelWordCount)+{1'b0, scratch_write_addr_i[lane][14:2]}][7:0] <=
scratch_write_data_i[lane][7:0];
for (int bank = 0; bank < BankCount; bank++) begin
for (int lane = 0; lane < 20; lane++) begin
if (s_issue_read[bank] && s_scratch_read_pending_q[lane] && (scratch_bank(
s_scratch_read_addr_q[lane]
) == 4'(bank)) && (s_scratch_read_addr_q[lane][14:5] == s_bank_addr[bank])) begin
s_issue_scratch_mask[bank][lane] = 1'b1;
end
if (scratch_write_strb_i[lane][1]) begin
mem[14'(ModelWordCount)+{1'b0, scratch_write_addr_i[lane][14:2]}][15:8] <=
scratch_write_data_i[lane][15:8];
end
if (scratch_write_strb_i[lane][2]) begin
mem[14'(ModelWordCount)+{1'b0, scratch_write_addr_i[lane][14:2]}][23:16] <=
scratch_write_data_i[lane][23:16];
end
if (scratch_write_strb_i[lane][3]) begin
mem[14'(ModelWordCount)+{1'b0, scratch_write_addr_i[lane][14:2]}][31:24] <=
scratch_write_data_i[lane][31:24];
end
if ((scratch_write_addr_i[lane] >= `RETROSOC_APU_KWS__SCRATCH_FIR_BASE) &&
(scratch_write_addr_i[lane] <
(`RETROSOC_APU_KWS__SCRATCH_FIR_BASE + 16'(FirEntryCount * 2)))) begin
s_fir_valid_q[6'(
(scratch_write_addr_i[lane] - `RETROSOC_APU_KWS__SCRATCH_FIR_BASE) >> 1
)] <= 1'b1;
end
for (int lane = 0; lane < 16; lane++) begin
if (s_issue_read[bank] && s_model_pending_q[lane] && (model_bank(
s_model_addr_q[lane]
) == 4'(bank)) && (s_model_addr_q[lane][14:5] == s_bank_addr[bank])) begin
s_issue_model_mask[bank][lane] = 1'b1;
end
end
end
end
end
for (genvar bank = 0; bank < BankCount; bank++) begin : gen_kws_bank
`ifdef HAVE_SRAM_MACRO
tc_sram_1024x32 u_kws_sram (
.clk_i (clk_i),
.cs_i (s_bank_cs[bank]),
.addr_i(s_bank_addr[bank]),
.data_i(s_bank_wdata[bank]),
.mask_i(s_bank_wmask[bank]),
.wren_i(s_bank_wren[bank]),
.data_o(s_bank_rdata[bank])
);
`elsif PDK_BEHAV
tc_sram_1024x32 u_kws_sram (
.clk_i (clk_i),
.cs_i (s_bank_cs[bank]),
.addr_i(s_bank_addr[bank]),
.data_i(s_bank_wdata[bank]),
.mask_i(s_bank_wmask[bank]),
.wren_i(s_bank_wren[bank]),
.data_o(s_bank_rdata[bank])
);
`else
`ifndef SYNTHESIS
logic [31:0] s_read_data_q;
assign s_bank_rdata[bank] = s_read_data_q;
always_ff @(posedge clk_i) begin
if (s_bank_cs[bank]) begin
if (s_bank_wren[bank]) begin
if (s_bank_wmask[bank][0]) begin
mem[bank_word(4'(bank), s_bank_addr[bank])][7:0] <= s_bank_wdata[bank][7:0];
end
if (s_bank_wmask[bank][1]) begin
mem[bank_word(4'(bank), s_bank_addr[bank])][15:8] <= s_bank_wdata[bank][15:8];
end
if (s_bank_wmask[bank][2]) begin
mem[bank_word(4'(bank), s_bank_addr[bank])][23:16] <= s_bank_wdata[bank][23:16];
end
if (s_bank_wmask[bank][3]) begin
mem[bank_word(4'(bank), s_bank_addr[bank])][31:24] <= s_bank_wdata[bank][31:24];
end
end else begin
s_read_data_q <= mem[bank_word(4'(bank), s_bank_addr[bank])];
end
end
end
`else
logic [31:0] s_storage_q [0:1023];
logic [31:0] s_read_data_q;
assign s_bank_rdata[bank] = s_read_data_q;
always_ff @(posedge clk_i) begin
if (s_bank_cs[bank]) begin
if (s_bank_wren[bank]) begin
if (s_bank_wmask[bank][0]) begin
s_storage_q[s_bank_addr[bank]][7:0] <= s_bank_wdata[bank][7:0];
end
if (s_bank_wmask[bank][1]) begin
s_storage_q[s_bank_addr[bank]][15:8] <= s_bank_wdata[bank][15:8];
end
if (s_bank_wmask[bank][2]) begin
s_storage_q[s_bank_addr[bank]][23:16] <= s_bank_wdata[bank][23:16];
end
if (s_bank_wmask[bank][3]) begin
s_storage_q[s_bank_addr[bank]][31:24] <= s_bank_wdata[bank][31:24];
end
end else begin
s_read_data_q <= s_storage_q[s_bank_addr[bank]];
end
end
end
`endif
`endif
end
always_ff @(posedge clk_i or negedge rst_n_i) begin
if (!rst_n_i) begin
s_busy_q <= 1'b0;
s_model_pending_q <= 16'd0;
s_model_addr_q <= '0;
s_scratch_read_pending_q <= 20'd0;
s_scratch_read_addr_q <= '0;
s_scratch_write_pending_q <= 6'd0;
s_scratch_write_addr_q <= '0;
s_scratch_write_data_q <= '0;
s_scratch_write_strb_q <= '0;
s_read_pipe_valid_q <= BankCount'(0);
s_read_pipe_model_q <= '0;
s_read_pipe_scratch_q <= '0;
s_fir_valid_q <= FirEntryCount'(0);
model_data_o <= '0;
scratch_read_data_o <= '0;
s_loader_read_pending_q <= 1'b0;
s_loader_read_bank_q <= 4'd0;
s_loader_read_err_q <= 1'b0;
end else begin
if (scratch_clear_i) s_fir_valid_q <= FirEntryCount'(0);
if (access_done_o) begin
s_busy_q <= 1'b0;
end else if (access_req_i && access_ready_o) begin
s_busy_q <= 1'b1;
s_model_pending_q <= access_write_i ? 16'd0 : model_read_valid_i;
s_model_addr_q <= model_addr_i;
s_scratch_read_pending_q <= access_write_i ? 20'd0 : scratch_read_valid_i;
s_scratch_read_addr_q <= scratch_read_addr_i;
s_scratch_write_pending_q <= access_write_i ? scratch_write_valid_i : 6'd0;
s_scratch_write_addr_q <= scratch_write_addr_i;
s_scratch_write_data_q <= scratch_write_data_i;
s_scratch_write_strb_q <= scratch_write_strb_i;
end
for (int bank = 0; bank < BankCount; bank++) begin
if (s_issue_write[bank]) begin
s_scratch_write_pending_q[s_issue_write_lane[bank]] <= 1'b0;
if ((s_scratch_write_addr_q[s_issue_write_lane[bank]] >=
`RETROSOC_APU_KWS__SCRATCH_FIR_BASE) &&
(s_scratch_write_addr_q[s_issue_write_lane[bank]] <
(`RETROSOC_APU_KWS__SCRATCH_FIR_BASE + 16'(FirEntryCount * 2)))) begin
s_fir_valid_q[6'((s_scratch_write_addr_q[s_issue_write_lane[bank]] -
`RETROSOC_APU_KWS__SCRATCH_FIR_BASE) >> 1)] <= 1'b1;
end
end
if (s_issue_read[bank]) begin
for (int lane = 0; lane < 16; lane++) begin
if (s_issue_model_mask[bank][lane]) s_model_pending_q[lane] <= 1'b0;
end
for (int lane = 0; lane < 20; lane++) begin
if (s_issue_scratch_mask[bank][lane]) begin
s_scratch_read_pending_q[lane] <= 1'b0;
end
end
end
s_read_pipe_valid_q[bank] <= s_issue_read[bank];
s_read_pipe_model_q[bank] <= s_issue_model_mask[bank];
s_read_pipe_scratch_q[bank] <= s_issue_scratch_mask[bank];
if (s_read_pipe_valid_q[bank]) begin
for (int lane = 0; lane < 16; lane++) begin
if (s_read_pipe_model_q[bank][lane]) begin
model_data_o[lane] <= s_bank_rdata[bank][8*s_model_addr_q[lane][1:0]+:8];
end
end
for (int lane = 0; lane < 20; lane++) begin
if (s_read_pipe_scratch_q[bank][lane]) begin
if ((s_scratch_read_addr_q[lane] >= `RETROSOC_APU_KWS__SCRATCH_FIR_BASE) &&
(s_scratch_read_addr_q[lane] <
(`RETROSOC_APU_KWS__SCRATCH_FIR_BASE + 16'(FirEntryCount * 2))) &&
!s_fir_valid_q[6'((s_scratch_read_addr_q[lane] -
`RETROSOC_APU_KWS__SCRATCH_FIR_BASE) >> 1)]) begin
scratch_read_data_o[lane] <= 32'd0;
end else begin
scratch_read_data_o[lane] <= s_bank_rdata[bank];
end
end
end
end
end
s_loader_read_pending_q <= 1'b0;
if (req_i && ready_o && s_loader_range_ok && !write_i) begin
s_loader_read_pending_q <= 1'b1;
s_loader_read_bank_q <= s_loader_bank;
s_loader_read_err_q <= 1'b0;
end else if (req_i && ready_o && !s_loader_range_ok) begin
s_loader_read_pending_q <= 1'b1;
s_loader_read_err_q <= 1'b1;
end
end
end
endmodule
+80 -56
View File
@@ -18,62 +18,86 @@ module jpeg_table_register_bank (
output logic [1279:0] ac_length_o
// verilog_format: on
);
for (genvar index = 0; index < 64; index++) begin : gen_quant_entry
dffl #(
.DATA_WIDTH(8)
) u_quant_dffl (
.clk_i(clk_i),
.en_i (write_i && (entry_kind_i < 4'd4) && (entry_index_i == 8'(index))),
.dat_i(entry_data_i[7:0]),
.dat_o(quant_o[index*8+:8])
);
dffl #(
.DATA_WIDTH(25)
) u_reciprocal_dffl (
.clk_i(clk_i),
.en_i (write_i && (entry_kind_i < 4'd4) && (entry_index_i == 8'(index))),
.dat_i(entry_reciprocal_i),
.dat_o(reciprocal_o[index*25+:25])
);
logic [ 511:0] s_quant_d;
logic [1599:0] s_reciprocal_d;
logic [ 191:0] s_dc_code_d;
logic [ 59:0] s_dc_len_d;
logic [4095:0] s_ac_code_d;
logic [1279:0] s_ac_len_d;
logic s_quant_write, s_dc_write, s_ac_write;
assign s_quant_write = write_i && (entry_kind_i < 4'd4) && (entry_index_i < 8'd64);
assign s_dc_write = write_i && (entry_kind_i >= 4'd4) && (entry_kind_i < 4'd8) &&
(entry_index_i < 8'd12);
assign s_ac_write = write_i && (entry_kind_i >= 4'd8);
always_comb begin
s_quant_d = quant_o;
s_reciprocal_d = reciprocal_o;
s_dc_code_d = dc_code_o;
s_dc_len_d = dc_length_o;
s_ac_code_d = ac_code_o;
s_ac_len_d = ac_length_o;
if (s_quant_write) begin
s_quant_d[entry_index_i*8+:8] = entry_data_i[7:0];
s_reciprocal_d[entry_index_i*25+:25] = entry_reciprocal_i;
end
if (s_dc_write) begin
s_dc_code_d[entry_index_i*16+:16] = entry_data_i[15:0];
s_dc_len_d[entry_index_i*5+:5] = entry_data_i[20:16];
end
if (s_ac_write) begin
s_ac_code_d[entry_index_i*16+:16] = entry_data_i[15:0];
s_ac_len_d[entry_index_i*5+:5] = entry_data_i[20:16];
end
end
for (genvar index = 0; index < 12; index++) begin : gen_dc_entry
dffl #(
.DATA_WIDTH(16)
) u_code_dffl (
.clk_i(clk_i),
.en_i (write_i && (entry_kind_i >= 4'd4) && (entry_kind_i < 4'd8) &&
(entry_index_i == 8'(index))),
.dat_i(entry_data_i[15:0]),
.dat_o(dc_code_o[index*16+:16])
);
dffl #(
.DATA_WIDTH(5)
) u_length_dffl (
.clk_i(clk_i),
.en_i (write_i && (entry_kind_i >= 4'd4) && (entry_kind_i < 4'd8) &&
(entry_index_i == 8'(index))),
.dat_i(entry_data_i[20:16]),
.dat_o(dc_length_o[index*5+:5])
);
end
for (genvar index = 0; index < 256; index++) begin : gen_ac_entry
dffl #(
.DATA_WIDTH(16)
) u_code_dffl (
.clk_i(clk_i),
.en_i (write_i && (entry_kind_i >= 4'd8) && (entry_index_i == 8'(index))),
.dat_i(entry_data_i[15:0]),
.dat_o(ac_code_o[index*16+:16])
);
dffl #(
.DATA_WIDTH(5)
) u_length_dffl (
.clk_i(clk_i),
.en_i (write_i && (entry_kind_i >= 4'd8) && (entry_index_i == 8'(index))),
.dat_i(entry_data_i[20:16]),
.dat_o(ac_length_o[index*5+:5])
);
end
dffl #(
.DATA_WIDTH(512)
) u_quant_dffl (
.clk_i(clk_i),
.en_i (s_quant_write),
.dat_i(s_quant_d),
.dat_o(quant_o)
);
dffl #(
.DATA_WIDTH(1600)
) u_reciprocal_dffl (
.clk_i(clk_i),
.en_i (s_quant_write),
.dat_i(s_reciprocal_d),
.dat_o(reciprocal_o)
);
dffl #(
.DATA_WIDTH(192)
) u_dc_code_dffl (
.clk_i(clk_i),
.en_i (s_dc_write),
.dat_i(s_dc_code_d),
.dat_o(dc_code_o)
);
dffl #(
.DATA_WIDTH(60)
) u_dc_length_dffl (
.clk_i(clk_i),
.en_i (s_dc_write),
.dat_i(s_dc_len_d),
.dat_o(dc_length_o)
);
dffl #(
.DATA_WIDTH(4096)
) u_ac_code_dffl (
.clk_i(clk_i),
.en_i (s_ac_write),
.dat_i(s_ac_code_d),
.dat_o(ac_code_o)
);
dffl #(
.DATA_WIDTH(1280)
) u_ac_length_dffl (
.clk_i(clk_i),
.en_i (s_ac_write),
.dat_i(s_ac_len_d),
.dat_o(ac_length_o)
);
endmodule
+40 -13
View File
@@ -6,6 +6,8 @@ import argparse
import json
import os
import re
import resource
import signal
import subprocess
import sys
import termios
@@ -75,6 +77,17 @@ def write_console_bytes(chunk: bytes) -> None:
sys.stdout.buffer.flush()
def terminate_process_group(process: subprocess.Popen[str] | subprocess.Popen[bytes]) -> None:
if process.poll() is not None:
return
os.killpg(process.pid, signal.SIGTERM)
try:
process.wait(timeout=5)
except subprocess.TimeoutExpired:
os.killpg(process.pid, signal.SIGKILL)
process.wait()
def main() -> int:
parser = argparse.ArgumentParser(description="Run a flow command with structured results")
parser.add_argument("--tool", required=True)
@@ -111,6 +124,28 @@ def main() -> int:
args.result.parent.mkdir(parents=True, exist_ok=True)
started = datetime.now(timezone.utc)
start_clock = time.monotonic()
atomic_write(
args.result,
json.dumps(
{
"schema_version": 1,
"tool": args.tool,
"command": command,
"started_at": started.isoformat(),
"status": "running",
"log": str(args.log.resolve()),
},
indent=2,
sort_keys=True,
)
+ "\n",
)
def interrupt_flow(_signum: int, _frame: object) -> None:
raise KeyboardInterrupt
signal.signal(signal.SIGINT, interrupt_flow)
signal.signal(signal.SIGTERM, interrupt_flow)
returncode = 127
error_message = None
process: subprocess.Popen[str] | subprocess.Popen[bytes] | None = None
@@ -132,6 +167,7 @@ def main() -> int:
errors=None if args.stream_bytes else "replace",
bufsize=0 if args.stream_bytes else 1,
pass_fds=jobserver_fds(),
start_new_session=True,
)
assert process.stdout is not None
if args.stream_bytes:
@@ -150,25 +186,15 @@ def main() -> int:
write_console_output(line)
if args.terminate_on_success_marker and args.success_marker in line:
marker_seen = True
process.terminate()
try:
process.wait(timeout=5)
except subprocess.TimeoutExpired:
process.kill()
process.wait()
terminate_process_group(process)
returncode = 1 if rejected_matches else 0
break
if not marker_seen:
returncode = process.wait()
except KeyboardInterrupt:
error_message = "interrupted"
if process is not None and process.poll() is None:
process.terminate()
try:
process.wait(timeout=5)
except subprocess.TimeoutExpired:
process.kill()
process.wait()
if process is not None:
terminate_process_group(process)
returncode = 130
except (OSError, subprocess.SubprocessError) as error:
error_message = str(error)
@@ -182,6 +208,7 @@ def main() -> int:
"started_at": started.isoformat(),
"finished_at": finished.isoformat(),
"duration_seconds": round(time.monotonic() - start_clock, 3),
"peak_rss_kib": resource.getrusage(resource.RUSAGE_CHILDREN).ru_maxrss,
"exit_code": returncode,
"status": "passed" if returncode == 0 else "failed",
"log": str(args.log.resolve()),
+28 -4
View File
@@ -40,7 +40,10 @@ module apu_kws_engine_tb;
logic [31:0] fault_addr_o, fault_detail_o;
logic [15:0][14:0] model_addr_o;
logic [15:0][7:0] model_data_i, model_store_data;
logic storage_req, storage_ready, storage_done, storage_progress, storage_write;
logic [15:0] model_read_valid;
logic scratch_clear;
logic [19:0] scratch_read_valid;
logic [19:0][15:0] scratch_read_addr;
logic [19:0][31:0] scratch_read_data;
logic [ 5:0] scratch_write_valid;
@@ -138,9 +141,16 @@ module apu_kws_engine_tb;
.data_o (),
.valid_o (),
.access_err_o (),
.access_req_i (storage_req),
.access_ready_o (storage_ready),
.access_done_o (storage_done),
.access_progress_o (storage_progress),
.access_write_i (storage_write),
.model_read_valid_i (model_read_valid),
.model_addr_i (model_addr_o),
.model_data_o (model_store_data),
.scratch_clear_i (scratch_clear),
.scratch_read_valid_i (scratch_read_valid),
.scratch_read_addr_i (scratch_read_addr),
.scratch_read_data_o (scratch_read_data),
.scratch_write_valid_i(scratch_write_valid),
@@ -195,9 +205,16 @@ module apu_kws_engine_tb;
.memory_error_detail_o (memory_error_detail_o),
.memory_input_used_o (memory_input_used_o),
.input_config_i (32'h01043e80),
.storage_req_o (storage_req),
.storage_ready_i (storage_ready),
.storage_done_i (storage_done),
.storage_progress_i (storage_progress),
.storage_write_o (storage_write),
.model_read_valid_o (model_read_valid),
.model_addr_o (model_addr_o),
.model_data_i (model_data_i),
.scratch_clear_o (scratch_clear),
.scratch_read_valid_o (scratch_read_valid),
.scratch_read_addr_o (scratch_read_addr),
.scratch_read_data_i (scratch_read_data),
.scratch_write_valid_o (scratch_write_valid),
@@ -474,15 +491,22 @@ module apu_kws_engine_tb;
enable_i = 1'b1;
accepted_samples = 0;
elapsed_cycles = 0;
while ((accepted_samples < 16000) && (elapsed_cycles < 2000000)) begin
while ((accepted_samples < 16000) && (elapsed_cycles < 4000000)) begin
@(posedge clk_i);
if (stream_i.tvalid && stream_i.tready) accepted_samples++;
elapsed_cycles++;
end
if (accepted_samples != 16000) $fatal(1, "KWS did not consume exactly one diagnostic window");
if (accepted_samples != 16000) begin
$fatal(
1,
"KWS input timeout accepted=%0d front=%0d infer=%0d wait=%0b req=%0b ready=%0b done=%0b",
accepted_samples, dut.s_front_state_q, dut.s_infer_state_q, dut.s_storage_wait_q,
storage_req, storage_ready, storage_done);
end
@(negedge clk_i);
enable_i = 1'b0;
while ((inference_count_o == 0) && (elapsed_cycles < 3000000)) begin
enable_i = 1'b0;
elapsed_cycles = 0;
while ((inference_count_o == 0) && (elapsed_cycles < 4000000)) begin
@(negedge clk_i);
elapsed_cycles++;
end
+63 -25
View File
@@ -9,10 +9,15 @@ module apu_kws_sram_client_tb;
logic [31:0] data_i = 32'd0;
logic [ 3:0] strb_i = 4'd0;
logic ready_o, valid_o, access_err_o;
logic [31:0] data_o;
logic [31:0] data_o;
logic access_req_i = 1'b0;
logic access_ready_o, access_done_o, access_progress_o;
logic access_write_i = 1'b0;
logic [15:0] model_read_valid_i = 16'd0;
logic [15:0][14:0] model_addr_i = '0;
logic [15:0][ 7:0] model_data_o;
logic scratch_clear_i = 1'b0;
logic [19:0] scratch_read_valid_i = 20'd0;
logic [19:0][15:0] scratch_read_addr_i = '0;
logic [19:0][31:0] scratch_read_data_o;
logic [ 5:0] scratch_write_valid_i = 6'd0;
@@ -39,9 +44,16 @@ module apu_kws_sram_client_tb;
.data_o (data_o),
.valid_o (valid_o),
.access_err_o (access_err_o),
.access_req_i (access_req_i),
.access_ready_o (access_ready_o),
.access_done_o (access_done_o),
.access_progress_o (access_progress_o),
.access_write_i (access_write_i),
.model_read_valid_i (model_read_valid_i),
.model_addr_i (model_addr_i),
.model_data_o (model_data_o),
.scratch_clear_i (scratch_clear_i),
.scratch_read_valid_i (scratch_read_valid_i),
.scratch_read_addr_i (scratch_read_addr_i),
.scratch_read_data_o (scratch_read_data_o),
.scratch_write_valid_i(scratch_write_valid_i),
@@ -88,6 +100,20 @@ module apu_kws_sram_client_tb;
end
endtask
task automatic run_access(input logic write_access_i);
begin
@(negedge clk_i);
access_write_i = write_access_i;
access_req_i = 1'b1;
if (!access_ready_o) $fatal(1, "KWS SRAM transaction was not accepted");
@(negedge clk_i);
access_req_i = 1'b0;
wait (access_done_o);
@(negedge clk_i);
access_write_i = 1'b0;
end
endtask
task automatic write_scratch(input logic [15:0] address_i, input logic [31:0] value_i,
input logic [3:0] strobe_i);
begin
@@ -96,11 +122,13 @@ module apu_kws_sram_client_tb;
scratch_write_addr_i[0] = address_i;
scratch_write_data_i[0] = value_i;
scratch_write_strb_i[0] = strobe_i;
@(negedge clk_i);
run_access(1'b1);
scratch_write_valid_i[0] = 1'b0;
scratch_write_strb_i[0] = 4'd0;
scratch_read_addr_i[0] = address_i;
#1;
scratch_read_valid_i[0] = 1'b1;
run_access(1'b0);
scratch_read_valid_i[0] = 1'b0;
if (scratch_read_data_o[0] != value_i) begin
$fatal(1, "scratch layout write mismatch at %04x", address_i);
end
@@ -126,25 +154,29 @@ module apu_kws_sram_client_tb;
rst_n_i = 1'b1;
write_model(`APB4_APU__LOCAL_KWS_BASE, 32'h4433_2211);
model_addr_i[0] = 15'd0;
model_addr_i[1] = 15'd1;
model_addr_i[2] = 15'd2;
model_addr_i[3] = 15'd3;
#1;
model_addr_i[0] = 15'd0;
model_addr_i[1] = 15'd1;
model_addr_i[2] = 15'd2;
model_addr_i[3] = 15'd3;
model_read_valid_i[3:0] = 4'hf;
run_access(1'b0);
model_read_valid_i = 16'd0;
if ({model_data_o[3], model_data_o[2], model_data_o[1], model_data_o[0]} != 32'h4433_2211) begin
$fatal(1, "banks10..17 model readback mismatch");
end
write_model(17'h1_0000, 32'h8877_6655);
write_model(`APB4_APU__LOCAL_KWS_BASE + `RETROSOC_APU_KWS__MODEL_BYTES - 4, 32'hccbb_aa99);
model_addr_i[0] = 15'h6000;
model_addr_i[1] = 15'h6001;
model_addr_i[2] = 15'h6002;
model_addr_i[3] = 15'h6003;
model_addr_i[4] = 15'h7ffc;
model_addr_i[5] = 15'h7ffd;
model_addr_i[6] = 15'h7ffe;
model_addr_i[7] = 15'h7fff;
#1;
model_addr_i[0] = 15'h6000;
model_addr_i[1] = 15'h6001;
model_addr_i[2] = 15'h6002;
model_addr_i[3] = 15'h6003;
model_addr_i[4] = 15'h7ffc;
model_addr_i[5] = 15'h7ffd;
model_addr_i[6] = 15'h7ffe;
model_addr_i[7] = 15'h7fff;
model_read_valid_i[7:0] = 8'hff;
run_access(1'b0);
model_read_valid_i = 16'd0;
if ({model_data_o[3], model_data_o[2], model_data_o[1], model_data_o[0]} != 32'h8877_6655) begin
$fatal(1, "APUM model address crossing 0x10000 did not map to bank16");
end
@@ -161,8 +193,10 @@ module apu_kws_sram_client_tb;
write_scratch(`RETROSOC_APU_KWS__SCRATCH_PEAK_BASE, 32'h6162_6364, 4'hf);
write_scratch(16'h7ffc, 32'h7172_7374, 4'hf);
model_addr_i[0] = 15'd0;
#1;
model_addr_i[0] = 15'd0;
model_read_valid_i[0] = 1'b1;
run_access(1'b0);
model_read_valid_i = 16'd0;
if (model_data_o[0] != 8'h11) $fatal(1, "scratch write corrupted APUM storage");
@(negedge clk_i);
@@ -185,12 +219,16 @@ module apu_kws_sram_client_tb;
@(negedge clk_i);
scratch_clear_i = 1'b1;
@(negedge clk_i);
scratch_clear_i = 1'b0;
scratch_read_addr_i[0] = `RETROSOC_APU_KWS__SCRATCH_FIR_BASE;
#1;
scratch_clear_i = 1'b0;
scratch_read_addr_i[0] = `RETROSOC_APU_KWS__SCRATCH_FIR_BASE;
scratch_read_valid_i[0] = 1'b1;
run_access(1'b0);
scratch_read_valid_i[0] = 1'b0;
if (scratch_read_data_o[0] != 32'd0) $fatal(1, "FIR lifecycle clear exposed stale data");
scratch_read_addr_i[0] = `RETROSOC_APU_KWS__SCRATCH_A_BASE;
#1;
scratch_read_addr_i[0] = `RETROSOC_APU_KWS__SCRATCH_A_BASE;
scratch_read_valid_i[0] = 1'b1;
run_access(1'b0);
scratch_read_valid_i[0] = 1'b0;
if (scratch_read_data_o[0] != 32'h0102_0304) begin
$fatal(1, "history clear corrupted non-history scratch");
end
@@ -203,5 +241,5 @@ module apu_kws_sram_client_tb;
end
logic s_unused;
assign s_unused = valid_o ^ ^data_o ^ codec_valid_o ^ ^codec_data_o;
assign s_unused = valid_o ^ ^data_o ^ codec_valid_o ^ ^codec_data_o ^ access_progress_o;
endmodule
+17
View File
@@ -46,7 +46,10 @@ module apu_p7_accuracy_tb;
logic [31:0] fault_addr_o, fault_detail_o;
logic [15:0][14:0] model_addr_o;
logic [15:0][ 7:0] model_store_data;
logic storage_req, storage_ready, storage_done, storage_progress, storage_write;
logic [15:0] model_read_valid;
logic scratch_clear;
logic [19:0] scratch_read_valid;
logic [19:0][15:0] scratch_read_addr;
logic [19:0][31:0] scratch_read_data;
logic [ 5:0] scratch_write_valid;
@@ -86,9 +89,16 @@ module apu_p7_accuracy_tb;
.data_o (),
.valid_o (),
.access_err_o (),
.access_req_i (storage_req),
.access_ready_o (storage_ready),
.access_done_o (storage_done),
.access_progress_o (storage_progress),
.access_write_i (storage_write),
.model_read_valid_i (model_read_valid),
.model_addr_i (model_addr_o),
.model_data_o (model_store_data),
.scratch_clear_i (scratch_clear),
.scratch_read_valid_i (scratch_read_valid),
.scratch_read_addr_i (scratch_read_addr),
.scratch_read_data_o (scratch_read_data),
.scratch_write_valid_i(scratch_write_valid),
@@ -143,9 +153,16 @@ module apu_p7_accuracy_tb;
.memory_input_used_o (memory_input_used_o),
.kws_config_i (KwsConfig),
.input_config_i (InputConfig),
.storage_req_o (storage_req),
.storage_ready_i (storage_ready),
.storage_done_i (storage_done),
.storage_progress_i (storage_progress),
.storage_write_o (storage_write),
.model_read_valid_o (model_read_valid),
.model_addr_o (model_addr_o),
.model_data_i (model_store_data),
.scratch_clear_o (scratch_clear),
.scratch_read_valid_o (scratch_read_valid),
.scratch_read_addr_o (scratch_read_addr),
.scratch_read_data_i (scratch_read_data),
.scratch_write_valid_o (scratch_write_valid),
+17
View File
@@ -49,7 +49,10 @@ module apu_p7_frontend_dump_tb;
logic [31:0] fault_addr_o, fault_detail_o;
logic [15:0][14:0] model_addr_o;
logic [15:0][ 7:0] model_store_data;
logic storage_req, storage_ready, storage_done, storage_progress, storage_write;
logic [15:0] model_read_valid;
logic scratch_clear;
logic [19:0] scratch_read_valid;
logic [19:0][15:0] scratch_read_addr;
logic [19:0][31:0] scratch_read_data;
logic [ 5:0] scratch_write_valid;
@@ -89,9 +92,16 @@ module apu_p7_frontend_dump_tb;
.data_o (),
.valid_o (),
.access_err_o (),
.access_req_i (storage_req),
.access_ready_o (storage_ready),
.access_done_o (storage_done),
.access_progress_o (storage_progress),
.access_write_i (storage_write),
.model_read_valid_i (model_read_valid),
.model_addr_i (model_addr_o),
.model_data_o (model_store_data),
.scratch_clear_i (scratch_clear),
.scratch_read_valid_i (scratch_read_valid),
.scratch_read_addr_i (scratch_read_addr),
.scratch_read_data_o (scratch_read_data),
.scratch_write_valid_i(scratch_write_valid),
@@ -146,9 +156,16 @@ module apu_p7_frontend_dump_tb;
.memory_input_used_o (memory_input_used_o),
.kws_config_i (KwsConfig),
.input_config_i (InputConfig),
.storage_req_o (storage_req),
.storage_ready_i (storage_ready),
.storage_done_i (storage_done),
.storage_progress_i (storage_progress),
.storage_write_o (storage_write),
.model_read_valid_o (model_read_valid),
.model_addr_o (model_addr_o),
.model_data_i (model_store_data),
.scratch_clear_o (scratch_clear),
.scratch_read_valid_o (scratch_read_valid),
.scratch_read_addr_o (scratch_read_addr),
.scratch_read_data_i (scratch_read_data),
.scratch_write_valid_o (scratch_write_valid),
+2
View File
@@ -1898,6 +1898,8 @@ def test_run_flow_writes_structured_result(tmp_path: Path) -> None:
assert data["status"] == "passed"
assert data["exit_code"] == 0
assert data["duration_seconds"] >= 0
assert isinstance(data["peak_rss_kib"], int)
assert data["peak_rss_kib"] > 0
assert log.read_text(encoding="utf-8") == "flow output\n"
+6
View File
@@ -55,7 +55,13 @@ def test_yosys_recipe_scripts_and_public_slot_are_stable() -> None:
assert "SYNTH_RECIPE" not in makefile.split("CONFIG_KEY_VARS", 1)[1].split("VARIANT_ID", 1)[0]
assert "--env SYNTH_RECIPE=$(SYNTH_RECIPE)" in yosys_mk
assert "--env YOSYS_TARGET_PERIOD_PS=$(YOSYS_TARGET_PERIOD_PS)" in yosys_mk
assert "YOSYS_TIMEOUT ?= 10800" in yosys_mk
assert "timeout --foreground --kill-after=5s $(YOSYS_TIMEOUT)s" in yosys_mk
assert "yosys -t --perffile $(YOSYS_BUILD)/yosys-perf.json" in yosys_mk
assert "abc_${synth_recipe}.script" in synth_tcl
assert '${proj_name}_pre_memory.rpt' in synth_tcl
assert '${proj_name}_pre_memory.json' in synth_tcl
assert synth_tcl.index('${proj_name}_pre_memory.json') < synth_tcl.index("yosys memory")
assert "yosys abc {*}$tech_cells_args -D $period_ps -script $abc_script -constr $abc_constr" in synth_tcl
assert "S110" not in synth_tcl
assert "$(SYN_BUILD_ROOT)/out/retrosoc_asic_yosys.v" in opensta