I’ve implemented custom arithmetic registers on a CW312T-A35 target using the SS2 wrapper and successfully verified the computation works correctly. However, the ChipWhisperer Husky scope
consistently fails to detect the trigger signal on TIO4, even though I’ve confirmed the signal is physically present using an external oscilloscope. The arithmetic operations complete
successfully (verified via register reads), but trace capture always times out.
Hardware Setup
- Scope: ChipWhisperer Husky
- Target: CW312T-A35 (Artix-7 35T FPGA)
- Platform: SS2 wrapper (ss2_a35)
- Clock: 7.37 MHz
- Bitstream: Custom arithmetic testing implementation based on ChipWhisperer AES example
- Connection: 20-pin cable between Husky and CW312T-A35
Implementation Details
Custom Arithmetic Registers
I added six custom registers to the standard CW305 register bank:
Input Registers:
* REG_NUM_1 = 0x0c (128-bit operand 1)
* REG_NUM_2 = 0x0d (128-bit operand 2)
* REG_NUM_3 = 0x0e (128-bit operand 3)
Output Registers:
* REG_ADD_OUT = 0x0f (addition result)
* REG_MUL_OUT = 0x10 (multiplication result)
* REG_DIV_OUT = 0x11 (division result)
Verilog FSM Modifications
Modified the FSM to generate a trigger signal on tio_trigger (routed to TIO4/IO4):
// core.v - FSM excerpt
localparam ARITH_CYCLES = 100; // Arithmetic completion cycles
localparam BUSY_HOLD_CYCLES = 5000; // Busy signal hold duration (\~680us)
S_WAIT: begin
// Perform arithmetic operations
add_o <= {64’h0, num_1\[63:0\]} + {64’h0, num_2\[63:0\]} + {64’h0, num_3\[63:0\]};
mul_o <= {64’h0, num_1\[63:0\]} \* {64’h0, num_2\[63:0\]};
div_o <= (num_2\[63:0\] != 0) ? ({64’h0, num_1\[63:0\]} / {64’h0, num_2\[63:0\]}) : 128’hFFFF…;
// Decrement counters
if (arith_counter > 0) arith_counter <= arith_counter - 1;
if (busy_counter > 0) busy_counter <= busy_counter - 1;
// Complete after arithmetic finishes
if (arith_counter == 0) begin
done_seen <= 1'b1;
state <= S_CAPTURE;
end
end
S_CAPTURE: begin
// Hold busy_o high for extended period
if (busy_counter == 0) begin
busy_o <= 1’b0;
state <= S_IDLE;
end else begin
busy_counter <= busy_counter - 1;
end
end
Signal routing in ss2_aes_wrapper.v:
wire tio_trigger_signal;
assign led2 = tio_trigger_signal; // For visual verification
assign io4 = tio_trigger_signal; // For scope trigger
cw305_top U_cw305_dut (
// … other ports …
.tio_trigger(tio_trigger_signal)
);
Wiring in cw305_top.v:
assign tio_trigger = aes_busy; // aes_busy comes from arithmetic_testing module
What Works
- Arithmetic Computation ✓
Register read/write and arithmetic operations work perfectly:
Test code
scope = cw.scope()
scope.clock.clkgen_freq = 7.37e6
scope.io.tio1 = “serial_rx”
scope.io.tio2 = “serial_tx”
scope.io.hs2 = ‘clkgen’
target = cw.target(scope, cw.targets.CW305, platform=‘ss2_a35’, program=False)
Write operands
def write_operand(target, reg_addr, value):
data = value.to_bytes(16, byteorder=‘little’)
target.fpga_write(reg_addr, list(data))
write_operand(target, 0x0c, 100) # NUM_1
write_operand(target, 0x0d, 200) # NUM_2
write_operand(target, 0x0e, 300) # NUM_3
Trigger computation
target.fpga_write(0x05, \[1\]) # REG_CRYPT_GO
time.sleep(0.01)
Read results
add_data = target.fpga_read(0x0f, 16)
add_result = int.from_bytes(bytes(add_data), byteorder=‘little’)
print(f"Result: {add_result}") # Output: 600 ✓
Result: Addition correctly computes 100+200+300=600. All arithmetic operations verified working.
- Trigger Signal Physically Present ✓
I confirmed the trigger signal with an external oscilloscope:
- Probe point: GPIO4 (IO4 pin on the 20-pin connector)
- Test: Sent 10 GO commands, observed 10 corresponding pulses
- Pulse width: Approximately 680 microseconds (matches BUSY_HOLD_CYCLES)
- Signal level: Valid logic levels detected
The trigger signal IS being generated and is physically present on the IO4 pin.
What Doesn’t Work
Scope Trigger Detection ✗
Despite the signal being present, the Husky scope consistently fails to detect the trigger:
Standard trigger configuration
scope.adc.samples = 1000
scope.adc.offset = 0
scope.adc.basic_mode = “rising_edge”
scope.trigger.triggers = “tio4”
scope.gain.db = 30
Write operands
write_operand(target, 0x0c, 100)
write_operand(target, 0x0d, 200)
write_operand(target, 0x0e, 300)
Arm and trigger
scope.arm()
time.sleep(0.001)
target.fpga_write(0x05, \[1\])
# Wait for capture
ret = scope.capture() # Returns False - TIMEOUT
Result: Timeout every time. No trace captured.
Debugging Attempts
- Verified Scope Configuration
print(f"scope.trigger.triggers = {scope.trigger.triggers}“) # tio4
print(f"scope.adc.basic_mode = {scope.adc.basic_mode}”) # rising_edge
print(f"scope.io.tio4 = {scope.io.tio4}“) # high_z
print(f"scope.trigger.module = {scope.trigger.module}”) # basic
All settings appear correct.
- Tried Multiple Trigger Configurations
- Rising edge trigger (default)
- Low-level trigger mode
- Extended timeout (5 seconds)
- Pre-trigger delay (100ms between arm and GO)
- Manual trigger mode
- Stream mode capture
All failed with timeout.
- Direct ADC Capture Test
Attempted to bypass trigger entirely and capture ADC samples directly:
scope.arm()
time.sleep(0.001)
target.fpga_write(0x05, \[1\])
time.sleep(0.05) # Wait for samples
trace = scope.get_last_trace() # Returns None
Result: scope.get_last_trace() returns None, suggesting the scope isn’t capturing ANY samples at all, even without trigger logic.
- LED Visual Verification
Routed trigger to LED2 - LED blinks as expected when GO commands sent, confirming FPGA-side trigger generation works.
Current Status
- ✓ Arithmetic computation: WORKING
- ✓ Trigger signal generation (FPGA): WORKING
- ✓ Trigger signal physical presence (oscilloscope): CONFIRMED
- ✗ Husky trigger detection: FAILING
- ✗ Trace capture: FAILING
Questions
- Is there a known issue with trigger detection on SS2 targets? The standard parallel USB CW305 may handle triggers differently than the SS2 wrapper.
- Could UART latency affect trigger detection? The sequence is: Python sends FPGA write via UART → FPGA processes command → trigger asserts. Could the ~300-500μs UART transmission delay cause
the scope to miss the trigger even with a 680μs pulse? - Are there alternative trigger methods for SS2 targets? Since external trigger detection fails, are there recommended approaches like:
- ADC-based triggering on power consumption changes
- Software triggering based on timing
- Post-capture trigger point identification
- Is TIO4 the correct pin for SS2 platform triggers? I’m using:
scope.trigger.triggers = “tio4” - Is this correct for SS2 targets, or should I use a different trigger source?
- Could this be a Husky-specific configuration issue? Are there additional Husky settings needed for SS2 target triggering that differ from standard CW305?
Request
Could someone provide guidance on:
- Proper trigger configuration for SS2 wrapped targets
- Why scope.get_last_trace() returns None even without trigger logic
- Alternative capture methods that might work better for this use case
- Whether this is a known limitation of SS2 targets with Husky
I can provide the complete Verilog source, Python test scripts, synthesis reports, or any other information needed to diagnose this issue.
Thank you for any assistance!