[fpga, sw] Enable SCA on ChipWhisperer CW310 FPGA board This involves the following main changes: - Two new outputs are defined on the CW310 chip-level to provide the target clock and capture trigger to the capture board. - The capture trigger can now be selected at run time through software and GPIO. This allows for taking SCA measurements for different IP cores (KMAC, OTBN) without having to re-generate a different bitstream. - The capture trigger is synchronized to the target clock (100 MHz). This is needed to prevent metastability issues in the scope depending on place and route on the target FPGA. - UART1 is enabled and muxed to pins IOC9/IOC8 using the pinmux. This is needed for the simple serial communication between target and capture board, while UART0 remains available for debug prints and logging. - The simple serial library is adjusted to use dif_uart_* only instead of a mix of dif_uart_* and base_printf() (this required the UART used for simple serial and stdout to be the same device previously). Signed-off-by: Pirmin Vogel <vogelpi@lowrisc.org>
diff --git a/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson b/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson index 6f8ec32..13b520b 100644 --- a/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson +++ b/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson
@@ -11320,6 +11320,20 @@ connection: manual desc: Manual USB UPHY signal for FPGA target } + { + name: IO_CLKOUT + type: BidirStd + bank: VCC + connection: manual + desc: Manual clock output for SCA setup + } + { + name: IO_TRIGGER + type: BidirStd + bank: VCC + connection: manual + desc: Manual trigger output for SCA setup + } ] } pinmux:
diff --git a/hw/top_earlgrey/data/clocks.xdc b/hw/top_earlgrey/data/clocks.xdc index c82c5cf..e020776 100644 --- a/hw/top_earlgrey/data/clocks.xdc +++ b/hw/top_earlgrey/data/clocks.xdc
@@ -27,5 +27,5 @@ create_clock -add -name clk_spi_in -period 100.00 -waveform {0 5} [get_pin top_*/u_spi_device/u_clk_spi_in_buf/gen_xilinx.u_impl_xilinx/bufg_i/O] create_clock -add -name clk_spi_out -period 100.00 -waveform {0 5} [get_pin top_*/u_spi_device/u_clk_spi_out_buf/gen_xilinx.u_impl_xilinx/bufg_i/O] -set_clock_groups -group ${clks_10_unbuf} -group ${clks_48_unbuf} -group ${clks_aon_unbuf} -group clk_io_div2 -group clk_io_div4 -group lc_jtag_tck -group rv_jtag_tck -group clk_spi_in -group clk_spi_out -asynchronous +set_clock_groups -group ${clks_10_unbuf} -group ${clks_48_unbuf} -group ${clks_aon_unbuf} -group clk_io_div2 -group clk_io_div4 -group lc_jtag_tck -group rv_jtag_tck -group clk_spi_in -group clk_spi_out -group sys_clk_pin -asynchronous
diff --git a/hw/top_earlgrey/data/pins_cw310.xdc b/hw/top_earlgrey/data/pins_cw310.xdc index fabacc7..6a2f58a 100644 --- a/hw/top_earlgrey/data/pins_cw310.xdc +++ b/hw/top_earlgrey/data/pins_cw310.xdc
@@ -60,18 +60,14 @@ set_property -dict { PACKAGE_PIN E10 IOSTANDARD LVCMOS33 } [get_ports { IOC5 }]; #USERIOB-14 set_property -dict { PACKAGE_PIN D8 IOSTANDARD LVCMOS33 } [get_ports { IOC6 }]; #USERIOB-16 set_property -dict { PACKAGE_PIN D9 IOSTANDARD LVCMOS33 } [get_ports { IOC7 }]; #USERIOB-18 -set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { IOC8 }]; #USERIOB-24 -set_property -dict { PACKAGE_PIN D10 IOSTANDARD LVCMOS33 } [get_ports { IOC9 }]; #USERIOB-26 +#set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { IOC8 }]; #USERIOB-24 +#set_property -dict { PACKAGE_PIN D10 IOSTANDARD LVCMOS33 } [get_ports { IOC9 }]; #USERIOB-26 ## ChipWhisperer 20-Pin Connector (J14) -## TODO: This needs to be adapted to enable captures on the CW310. In particular, -## - a precise capture trigger and the target clock need to be output, and -## - a separate UART should be used for the simpleserial communication with the capture board. -## See also chiplevel.sv.tpl -#set_property -dict { PACKAGE_PIN AE25 IOSTANDARD LVCMOS33 } [get_ports { IOC11 }]; #J14 PIN 10 CWIO_IO1 (UART) -#set_property -dict { PACKAGE_PIN AF25 IOSTANDARD LVCMOS33 } [get_ports { IOC10 }]; #J14 PIN 12 CWIO_IO2 (UART) -#set_property -dict { PACKAGE_PIN AF24 IOSTANDARD LVCMOS33 } [get_ports { IOB6 }]; #J14 PIN 16 CWIO_IO4 (Trigger) -#set_property -dict { PACKAGE_PIN AB21 IOSTANDARD LVCMOS33 } [get_ports { TIO_CLKOUT }]; #J14 PIN 4 CWIO_HS1 (Target clock) +set_property -dict { PACKAGE_PIN AF25 IOSTANDARD LVCMOS33 } [get_ports { IOC9 }]; #J14 PIN 12 CWIO_IO2 - OpenTitan UART1 TX +set_property -dict { PACKAGE_PIN AE25 IOSTANDARD LVCMOS33 } [get_ports { IOC8 }]; #J14 PIN 10 CWIO_IO1 - OpenTitan UART1 RX +set_property -dict { PACKAGE_PIN AF24 IOSTANDARD LVCMOS33 } [get_ports { IO_TRIGGER }]; #J14 PIN 16 CWIO_IO4 - Capture Trigger +set_property -dict { PACKAGE_PIN AB21 IOSTANDARD LVCMOS33 } [get_ports { IO_CLKOUT }]; #J14 PIN 4 CWIO_HS1 - Target clock ## TI TUSB1106 USB PHY usbdev testing set_property -dict { PACKAGE_PIN AF19 IOSTANDARD LVCMOS18 } [get_ports { IO_UPHY_DP_TX }]; #USRUSB_VPO @@ -93,8 +89,8 @@ set_property -dict { PACKAGE_PIN A13 IOSTANDARD LVCMOS33 } [get_ports { IO_USB_DPPULLUP0 }]; #USERIOB-27 ## UART -set_property -dict { PACKAGE_PIN AA22 IOSTANDARD LVCMOS33 } [get_ports { IOC11 }]; #UART1RXD -set_property -dict { PACKAGE_PIN W24 IOSTANDARD LVCMOS33 } [get_ports { IOC10 }]; #UART1TXD +set_property -dict { PACKAGE_PIN AA22 IOSTANDARD LVCMOS33 } [get_ports { IOC11 }]; #UART1RXD - OpenTitan UART0 TX +set_property -dict { PACKAGE_PIN W24 IOSTANDARD LVCMOS33 } [get_ports { IOC10 }]; #UART1TXD - OpenTitan UART0 RX ## Configuration options, can be used for all designs set_property CONFIG_VOLTAGE 3.3 [current_design]
diff --git a/hw/top_earlgrey/data/top_earlgrey.hjson b/hw/top_earlgrey/data/top_earlgrey.hjson index 6c9df7a..6df1b83 100644 --- a/hw/top_earlgrey/data/top_earlgrey.hjson +++ b/hw/top_earlgrey/data/top_earlgrey.hjson
@@ -1396,6 +1396,9 @@ { name: 'IO_UPHY_OE_N', type: 'BidirStd', bank: 'VCC', connection: 'manual', desc: 'Manual USB UPHY signal for FPGA target'} { name: 'IO_UPHY_SENSE', type: 'BidirStd', bank: 'VCC', connection: 'manual', desc: 'Manual USB UPHY signal for FPGA target'} { name: 'IO_UPHY_DPPULLUP', type: 'BidirStd', bank: 'VCC', connection: 'manual', desc: 'Manual USB UPHY signal for FPGA target'} + // ChipWhisperer IO + { name: 'IO_CLKOUT', type: 'BidirStd', bank: 'VCC', connection: 'manual', desc: 'Manual clock output for SCA setup'} + { name: 'IO_TRIGGER', type: 'BidirStd', bank: 'VCC', connection: 'manual', desc: 'Manual trigger output for SCA setup'} ], },
diff --git a/hw/top_earlgrey/rtl/autogen/chip_earlgrey_asic.sv b/hw/top_earlgrey/rtl/autogen/chip_earlgrey_asic.sv index 0ff33a3..4fa0959 100644 --- a/hw/top_earlgrey/rtl/autogen/chip_earlgrey_asic.sv +++ b/hw/top_earlgrey/rtl/autogen/chip_earlgrey_asic.sv
@@ -1159,5 +1159,4 @@ - endmodule : chip_earlgrey_asic
diff --git a/hw/top_earlgrey/rtl/autogen/chip_earlgrey_cw310.sv b/hw/top_earlgrey/rtl/autogen/chip_earlgrey_cw310.sv index c29e049..4870180 100644 --- a/hw/top_earlgrey/rtl/autogen/chip_earlgrey_cw310.sv +++ b/hw/top_earlgrey/rtl/autogen/chip_earlgrey_cw310.sv
@@ -38,6 +38,8 @@ inout IO_UPHY_OE_N, // Manual Pad inout IO_UPHY_SENSE, // Manual Pad inout IO_UPHY_DPPULLUP, // Manual Pad + inout IO_CLKOUT, // Manual Pad + inout IO_TRIGGER, // Manual Pad // Muxed Pads inout IOA0, // MIO Pad 0 @@ -216,6 +218,8 @@ logic manual_in_io_uphy_oe_n, manual_out_io_uphy_oe_n, manual_oe_io_uphy_oe_n; logic manual_in_io_uphy_sense, manual_out_io_uphy_sense, manual_oe_io_uphy_sense; logic manual_in_io_uphy_dppullup, manual_out_io_uphy_dppullup, manual_oe_io_uphy_dppullup; + logic manual_in_io_clkout, manual_out_io_clkout, manual_oe_io_clkout; + logic manual_in_io_trigger, manual_out_io_trigger, manual_oe_io_trigger; pad_attr_t manual_attr_por_n; pad_attr_t manual_attr_usb_p; @@ -233,6 +237,8 @@ pad_attr_t manual_attr_io_uphy_oe_n; pad_attr_t manual_attr_io_uphy_sense; pad_attr_t manual_attr_io_uphy_dppullup; + pad_attr_t manual_attr_io_clkout; + pad_attr_t manual_attr_io_trigger; ///////////////////////// // Stubbed pad tie-off // @@ -323,9 +329,11 @@ padring #( // Padring specific counts may differ from pinmux config due // to custom, stubbed or added pads. - .NDioPads(20), + .NDioPads(22), .NMioPads(29), .DioPadType ({ + BidirStd, // IO_TRIGGER + BidirStd, // IO_CLKOUT BidirStd, // IO_UPHY_DPPULLUP BidirStd, // IO_UPHY_SENSE BidirStd, // IO_UPHY_OE_N @@ -385,6 +393,8 @@ .dio_in_raw_o ( ), // Chip IOs .dio_pad_io ({ + IO_TRIGGER, + IO_CLKOUT, IO_UPHY_DPPULLUP, IO_UPHY_SENSE, IO_UPHY_OE_N, @@ -441,6 +451,8 @@ // Core-facing .dio_in_o ({ + manual_in_io_trigger, + manual_in_io_clkout, manual_in_io_uphy_dppullup, manual_in_io_uphy_sense, manual_in_io_uphy_oe_n, @@ -463,6 +475,8 @@ manual_in_por_n }), .dio_out_i ({ + manual_out_io_trigger, + manual_out_io_clkout, manual_out_io_uphy_dppullup, manual_out_io_uphy_sense, manual_out_io_uphy_oe_n, @@ -485,6 +499,8 @@ manual_out_por_n }), .dio_oe_i ({ + manual_oe_io_trigger, + manual_oe_io_clkout, manual_oe_io_uphy_dppullup, manual_oe_io_uphy_sense, manual_oe_io_uphy_oe_n, @@ -507,6 +523,8 @@ manual_oe_por_n }), .dio_attr_i ({ + manual_attr_io_trigger, + manual_attr_io_clkout, manual_attr_io_uphy_dppullup, manual_attr_io_uphy_sense, manual_attr_io_uphy_oe_n, @@ -724,7 +742,6 @@ // for verilator purposes, make these two the same. lc_ctrl_pkg::lc_tx_t lc_clk_bypass; - // TODO: align this with ASIC version to minimize the duplication. // Also need to add AST simulation and FPGA emulation models for things like entropy source - // otherwise Verilator / FPGA will hang. @@ -803,5 +820,59 @@ ); + ///////////////////////////////////////////////////// + // ChipWhisperer CW310/305 Capture Board Interface // + ///////////////////////////////////////////////////// + // This is used to interface OpenTitan as a target with a capture board trough the ChipWhisperer + // 20-pin connector. This is used for SCA/FI experiments only. + + logic unused_inputs; + assign unused_inputs = manual_in_io_clkout ^ manual_in_io_trigger; + + // Synchronous clock output to capture board. + assign manual_out_io_clkout = manual_in_io_clk; + assign manual_oe_io_clkout = 1'b1; + + // Capture trigger. + // We use the clkmgr_aon_idle signal of the IP of interest to form a precise capture trigger. + // GPIO[11:9] is used for selecting the IP of interest. The encoding is as follows (see + // hint_names_e enum in clkmgr_pkg.sv for details). + // + // IP - GPIO[11:9] - Index for clkmgr_aon_idle + // ------------------------------------------------------------ + // AES - 000 - 0 + // HMAC - 001 - 1 + // KMAC - 010 - 2 - not implemented on CW305 + // OTBN (IO_DIV4) - 011 - 3 - not implemented on CW305 + // OTBN - 100 - 4 - not implemented on CW305 + // + // In addition, GPIO8 is used for gating the capture trigger in software. + // Note that GPIO[11:8] are connected to LED[3:0] on the CW310. + // On the CW305, GPIO[9,8] are connected to LED[5,7]. + + clkmgr_pkg::hint_names_e trigger_sel; + always_comb begin : trigger_sel_mux + unique case ({mio_out[MioOutGpioGpio11], mio_out[MioOutGpioGpio10], mio_out[MioOutGpioGpio9]}) + 3'b000: trigger_sel = clkmgr_pkg::HintMainAes; + 3'b001: trigger_sel = clkmgr_pkg::HintMainHmac; + 3'b010: trigger_sel = clkmgr_pkg::HintMainKmac; + 3'b011: trigger_sel = clkmgr_pkg::HintIoDiv4Otbn; + 3'b100: trigger_sel = clkmgr_pkg::HintMainOtbn; + default: trigger_sel = clkmgr_pkg::HintMainAes; + endcase; + end + logic trigger, trigger_oe; + assign trigger = mio_out[MioOutGpioGpio8] & ~top_earlgrey.clkmgr_aon_idle[trigger_sel]; + assign trigger_oe = mio_oe[MioOutGpioGpio8]; + + // Synchronize trigger to manual_in_io_clk. + prim_flop_2sync #( + .Width ( 2 ) + ) u_sync_trigger ( + .clk_i ( manual_in_io_clk ), + .rst_ni ( manual_in_por_n ), + .d_i ( {trigger, trigger_oe} ), + .q_o ( {manual_out_io_trigger, manual_oe_io_trigger} ) + ); endmodule : chip_earlgrey_cw310
diff --git a/hw/top_earlgrey/rtl/autogen/chip_earlgrey_nexysvideo.sv b/hw/top_earlgrey/rtl/autogen/chip_earlgrey_nexysvideo.sv index 6090110..1950931 100644 --- a/hw/top_earlgrey/rtl/autogen/chip_earlgrey_nexysvideo.sv +++ b/hw/top_earlgrey/rtl/autogen/chip_earlgrey_nexysvideo.sv
@@ -724,7 +724,6 @@ // for verilator purposes, make these two the same. lc_ctrl_pkg::lc_tx_t lc_clk_bypass; - // TODO: align this with ASIC version to minimize the duplication. // Also need to add AST simulation and FPGA emulation models for things like entropy source - // otherwise Verilator / FPGA will hang. @@ -808,5 +807,4 @@ ); - endmodule : chip_earlgrey_nexysvideo
diff --git a/hw/top_englishbreakfast/data/pins_cw305.xdc b/hw/top_englishbreakfast/data/pins_cw305.xdc index ad5bcd2..1aec16d 100644 --- a/hw/top_englishbreakfast/data/pins_cw305.xdc +++ b/hw/top_englishbreakfast/data/pins_cw305.xdc
@@ -40,6 +40,7 @@ set_property -dict { PACKAGE_PIN F15 IOSTANDARD LVCMOS33 } [get_ports { IOB3 }]; #JP3.F15 set_property -dict { PACKAGE_PIN E11 IOSTANDARD LVCMOS33 } [get_ports { IOB4 }]; #JP3.E11 set_property -dict { PACKAGE_PIN F13 IOSTANDARD LVCMOS33 } [get_ports { IOB5 }]; #JP3.F13 +set_property -dict { PACKAGE_PIN A12 IOSTANDARD LVCMOS33 } [get_ports { IOB6 }]; #JP3.A12 set_property -dict { PACKAGE_PIN C16 IOSTANDARD LVCMOS33 DRIVE 8 SLEW FAST } [get_ports { USB_P }]; #JP3.C16 set_property -dict { PACKAGE_PIN D13 IOSTANDARD LVCMOS33 DRIVE 8 SLEW FAST } [get_ports { USB_N }]; #JP3.D13 @@ -49,14 +50,14 @@ set_property -dict { PACKAGE_PIN G16 IOSTANDARD LVCMOS33 } [get_ports { IO_UTX_DEBUG }]; #JP3.G16 (UART) for debugging -## Unused pins of JP3: A12, B12, F12 +## Unused pins of JP3: B12, F12 ## 20-Pin Connector (JP1) -set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { IOC11 }]; #JP1 PIN 10 (UART) -set_property -dict { PACKAGE_PIN P16 IOSTANDARD LVCMOS33 } [get_ports { IOC10 }]; #JP1 PIN 12 (UART) -set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { IOB6 }]; #JP1 PIN 16 TIO4 (Trigger) -set_property -dict { PACKAGE_PIN M16 IOSTANDARD LVCMOS33 } [get_ports { TIO_CLKOUT }]; #JP1 PIN 4 TIO_HS1. Clock sync capture board. +set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { IOC11 }]; #JP1 PIN 12 TIO2 - OpenTitan UART0 TX +set_property -dict { PACKAGE_PIN P16 IOSTANDARD LVCMOS33 } [get_ports { IOC10 }]; #JP1 PIN 10 TIO1 - OpenTitan UART0 RX +set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { IO_TRIGGER }]; #JP1 PIN 16 TIO4 - Capture Trigger +set_property -dict { PACKAGE_PIN M16 IOSTANDARD LVCMOS33 } [get_ports { IO_CLKOUT }]; #JP1 PIN 4 TIO_HS1 - Target clock ## USB Connector
diff --git a/hw/top_englishbreakfast/data/top_englishbreakfast.hjson b/hw/top_englishbreakfast/data/top_englishbreakfast.hjson index 5da4319..9c4c8d1 100644 --- a/hw/top_englishbreakfast/data/top_englishbreakfast.hjson +++ b/hw/top_englishbreakfast/data/top_englishbreakfast.hjson
@@ -981,8 +981,9 @@ { name: 'IO_USB_DNPULLUP0', type: 'BidirStd', bank: 'VCC', connection: 'manual', desc: 'Manual USB signal for FPGA target'} { name: 'IO_USB_DPPULLUP0', type: 'BidirStd', bank: 'VCC', connection: 'manual', desc: 'Manual USB signal for FPGA target'} // ChipWhisperer IO - { name: 'TIO_CLKOUT', type: 'BidirStd', bank: 'VCC', connection: 'manual', desc: 'Manual clock output for SCA setup'} - { name: 'IO_UTX_DEBUG', type: 'BidirStd', bank: 'VCC', connection: 'manual', desc: 'Manual UART TX debug output' } + { name: 'IO_CLKOUT', type: 'BidirStd', bank: 'VCC', connection: 'manual', desc: 'Manual clock output for SCA setup'} + { name: 'IO_TRIGGER', type: 'BidirStd', bank: 'VCC', connection: 'manual', desc: 'Manual trigger output for SCA setup'} + { name: 'IO_UTX_DEBUG', type: 'BidirStd', bank: 'VCC', connection: 'manual', desc: 'Manual UART TX debug output'} ], }
diff --git a/sw/device/lib/pinmux.c b/sw/device/lib/pinmux.c index 476429a..8861f54 100644 --- a/sw/device/lib/pinmux.c +++ b/sw/device/lib/pinmux.c
@@ -41,7 +41,7 @@ PINMUX_MIO_OUTSEL_0_OUT_0_MASK, PINMUX_PERIPH_OUTSEL_IDX_OFFSET); - // Configure UART RX input to connect to MIO pad IOR2 + // Configure UART0 RX input to connect to MIO pad IOC10 mmio_region_t reg32 = mmio_region_from_addr( PINMUX0_BASE_ADDR + PINMUX_MIO_PERIPH_INSEL_0_REG_OFFSET); uint32_t reg_value = kTopEarlgreyPinmuxInselIoc10; @@ -51,7 +51,7 @@ uint32_t mask = PINMUX_MIO_PERIPH_INSEL_0_IN_0_MASK; mmio_region_write32(reg32, reg_offset, reg_value & mask); - // Configure UART TX output to connect to MIO pad IOR3 + // Configure UART0 TX output to connect to MIO pad IOC11 reg32 = mmio_region_from_addr(PINMUX0_BASE_ADDR + PINMUX_MIO_OUTSEL_0_REG_OFFSET); reg_value = kTopEarlgreyPinmuxOutselUart0Tx; @@ -60,4 +60,24 @@ reg_offset = kTopEarlgreyPinmuxMioOutIoc11 << 2; mask = PINMUX_MIO_OUTSEL_0_OUT_0_MASK; mmio_region_write32(reg32, reg_offset, reg_value & mask); + + // Configure UART1 RX input to connect to MIO pad IOC8 + reg32 = mmio_region_from_addr(PINMUX0_BASE_ADDR + + PINMUX_MIO_PERIPH_INSEL_0_REG_OFFSET); + reg_value = kTopEarlgreyPinmuxInselIoc8; + // We've got one insel configuration field per register. Hence, we have to + // convert the enumeration index into a byte address using << 2. + reg_offset = kTopEarlgreyPinmuxPeripheralInUart1Rx << 2; + mask = PINMUX_MIO_PERIPH_INSEL_0_IN_0_MASK; + mmio_region_write32(reg32, reg_offset, reg_value & mask); + + // Configure UART1 TX output to connect to MIO pad IOC9 + reg32 = + mmio_region_from_addr(PINMUX0_BASE_ADDR + PINMUX_MIO_OUTSEL_0_REG_OFFSET); + reg_value = kTopEarlgreyPinmuxOutselUart1Tx; + // We've got one insel configuration field per register. Hence, we have to + // convert the enumeration index into a byte address using << 2. + reg_offset = kTopEarlgreyPinmuxMioOutIoc9 << 2; + mask = PINMUX_MIO_OUTSEL_0_OUT_0_MASK; + mmio_region_write32(reg32, reg_offset, reg_value & mask); }
diff --git a/sw/device/sca/aes_serial.c b/sw/device/sca/aes_serial.c index 372421e..a6cd8c0 100644 --- a/sw/device/sca/aes_serial.c +++ b/sw/device/sca/aes_serial.c
@@ -198,18 +198,23 @@ * UART. */ int main(void) { - const dif_uart_t *uart; + const dif_uart_t *uart1; sca_init(); - sca_get_uart(&uart); + sca_get_uart(&uart1); - simple_serial_init(uart); + LOG_INFO("Running AES serial"); + + LOG_INFO("Initializing simple serial interface to capture board."); + simple_serial_init(uart1); simple_serial_register_handler('k', aes_serial_set_key); simple_serial_register_handler('p', aes_serial_single_encrypt); simple_serial_register_handler('b', aes_serial_batch_encrypt); + LOG_INFO("Initializing AES unit."); init_aes(); + LOG_INFO("Starting simple serial packet handling."); while (true) { simple_serial_process_packet(); }
diff --git a/sw/device/sca/lib/sca.c b/sw/device/sca/lib/sca.c index 87c6147..758d330 100644 --- a/sw/device/sca/lib/sca.c +++ b/sw/device/sca/lib/sca.c
@@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "sw/device/sca/lib/sca.h" + #include "sw/device/lib/arch/device.h" #include "sw/device/lib/dif/dif_gpio.h" #include "sw/device/lib/dif/dif_rv_timer.h" @@ -27,8 +28,15 @@ enum { /** * GPIO capture trigger values. + * + * GPIO10[11:9]: Trigger select, 000 for AES, see chiplevel.sv.tpl for + * details. + * GPIO8: Trigger enable */ - kGpioCaptureTriggerHigh = 0x08200, + kGpioCaptureTriggerSelMask = 0x00E00, + kGpioCaptureTriggerEnMask = 0x00100, + kGpioCaptureTriggerSel = 0x00000, + kGpioCaptureTriggerHigh = 0x00100, kGpioCaptureTriggerLow = 0x00000, /** * RV timer settings. @@ -37,7 +45,8 @@ kRvTimerHart = kTopEarlgreyPlicTargetIbex0, }; -static dif_uart_t uart; +static dif_uart_t uart0; +static dif_uart_t uart1; static dif_gpio_t gpio; static dif_rv_timer_t timer; @@ -47,19 +56,27 @@ * Initializes the UART peripheral. */ static void sca_init_uart(void) { + const dif_uart_config_t uart_config = { + .baudrate = kUartBaudrate, + .clk_freq_hz = kClockFreqPeripheralHz, + .parity_enable = kDifUartToggleDisabled, + .parity = kDifUartParityEven, + }; + IGNORE_RESULT(dif_uart_init( (dif_uart_params_t){ .base_addr = mmio_region_from_addr(TOP_EARLGREY_UART0_BASE_ADDR), }, - &uart)); - IGNORE_RESULT( - dif_uart_configure(&uart, (dif_uart_config_t){ - .baudrate = kUartBaudrate, - .clk_freq_hz = kClockFreqPeripheralHz, - .parity_enable = kDifUartToggleDisabled, - .parity = kDifUartParityEven, - })); - base_uart_stdout(&uart); + &uart0)); + IGNORE_RESULT(dif_uart_configure(&uart0, uart_config)); + base_uart_stdout(&uart0); + + IGNORE_RESULT(dif_uart_init( + (dif_uart_params_t){ + .base_addr = mmio_region_from_addr(TOP_EARLGREY_UART1_BASE_ADDR), + }, + &uart1)); + IGNORE_RESULT(dif_uart_configure(&uart1, uart_config)); } /** @@ -69,8 +86,10 @@ dif_gpio_params_t gpio_params = { .base_addr = mmio_region_from_addr(TOP_EARLGREY_GPIO_BASE_ADDR)}; IGNORE_RESULT(dif_gpio_init(gpio_params, &gpio)); - IGNORE_RESULT( - dif_gpio_output_set_enabled_all(&gpio, kGpioCaptureTriggerHigh)); + IGNORE_RESULT(dif_gpio_output_set_enabled_all( + &gpio, kGpioCaptureTriggerSelMask | kGpioCaptureTriggerEnMask)); + IGNORE_RESULT(dif_gpio_write_masked(&gpio, kGpioCaptureTriggerSelMask, + kGpioCaptureTriggerSel)); } /** @@ -112,14 +131,16 @@ sca_init_timer(); } -void sca_get_uart(const dif_uart_t **uart_out) { *uart_out = &uart; } +void sca_get_uart(const dif_uart_t **uart_out) { *uart_out = &uart1; } void sca_set_trigger_high() { - IGNORE_RESULT(dif_gpio_write_all(&gpio, kGpioCaptureTriggerHigh)); + IGNORE_RESULT(dif_gpio_write_masked(&gpio, kGpioCaptureTriggerEnMask, + kGpioCaptureTriggerHigh)); } void sca_set_trigger_low() { - IGNORE_RESULT(dif_gpio_write_all(&gpio, kGpioCaptureTriggerLow)); + IGNORE_RESULT(dif_gpio_write_masked(&gpio, kGpioCaptureTriggerEnMask, + kGpioCaptureTriggerLow)); } void sca_call_and_sleep(sca_callee callee, uint32_t sleep_cycles) {
diff --git a/sw/device/sca/lib/simple_serial.c b/sw/device/sca/lib/simple_serial.c index 2c4ebe5..c07f94f 100644 --- a/sw/device/sca/lib/simple_serial.c +++ b/sw/device/sca/lib/simple_serial.c
@@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "sw/device/sca/lib/simple_serial.h" + #include "sw/device/lib/arch/device.h" #include "sw/device/lib/base/memory.h" #include "sw/device/lib/dif/dif_uart.h" @@ -205,9 +206,12 @@ void simple_serial_send_packet(const uint8_t cmd, const uint8_t *data, size_t data_len) { - base_printf("%c", cmd); + char buf; + base_snprintf(&buf, 1, "%c", cmd); + IGNORE_RESULT(dif_uart_byte_send_polled(uart, buf)); simple_serial_print_hex(data, data_len); - base_printf("\n"); + base_snprintf(&buf, 1, "\n"); + IGNORE_RESULT(dif_uart_byte_send_polled(uart, buf)); } void simple_serial_send_status(uint8_t res) { @@ -215,7 +219,10 @@ } void simple_serial_print_hex(const uint8_t *data, size_t data_len) { + char buf[2]; for (size_t i = 0; i < data_len; ++i) { - base_printf("%2x", data[i]); + base_snprintf(&buf[0], 2, "%2x", data[i]); + IGNORE_RESULT(dif_uart_byte_send_polled(uart, buf[0])); + IGNORE_RESULT(dif_uart_byte_send_polled(uart, buf[1])); } }
diff --git a/util/topgen/templates/chiplevel.sv.tpl b/util/topgen/templates/chiplevel.sv.tpl index 2bd7596..5426c00 100644 --- a/util/topgen/templates/chiplevel.sv.tpl +++ b/util/topgen/templates/chiplevel.sv.tpl
@@ -1060,11 +1060,6 @@ // for verilator purposes, make these two the same. lc_ctrl_pkg::lc_tx_t lc_clk_bypass; -% if target["name"] == "cw305": - // This is used for outputting the capture trigger - logic [pinmux_reg_pkg::NMioPads-1:0] mio_out_pre; -% endif - // TODO: align this with ASIC version to minimize the duplication. // Also need to add AST simulation and FPGA emulation models for things like entropy source - // otherwise Verilator / FPGA will hang. @@ -1141,11 +1136,7 @@ // Multiplexed I/O .mio_in_i ( mio_in ), -% if target["name"] == "cw305": - .mio_out_o ( mio_out_pre ), -% else: .mio_out_o ( mio_out ), -% endif .mio_oe_o ( mio_oe ), // Dedicated I/O @@ -1170,45 +1161,74 @@ ); % endif - ################################################################### -## CW305 capture board interface ## +## CW310/305 capture board interface ## ################################################################### -## TODO: This needs to be adapted to enable captures on the CW310. In particular, -## - a precise capture trigger and the target clock need to be output, and -## - a separate UART should be used for the simpleserial communication with the capture board. -## See also pins_cw310.xdc -% if target["name"] in ["cw305"]: +% if target["name"] in ["cw310", "cw305"]: - ////////////////////////////////////// - // Generate precise capture trigger // - ////////////////////////////////////// - - // TODO: make this a "manual" IO specific to the CW305 target - // such that we can decouple this from the MIO signals. - localparam int MioIdxTrigger = 15; - - // To obtain a more precise capture trigger for side-channel analysis, we only forward the - // software-controlled capture trigger when the AES module is actually busy (performing - // either encryption/decryption or clearing internal registers). - // GPIO15 is used as capture trigger (mapped to IOB6 at the moment in pinmux.c). - always_comb begin : p_trigger - mio_out = mio_out_pre; - mio_out[MioIdxTrigger] = mio_out_pre[MioIdxTrigger] & - ~top_${top["name"]}.clkmgr_aon_idle[clkmgr_pkg::HintMainAes]; - end - - ////////////////////// - // ChipWhisperer IO // - ////////////////////// + ///////////////////////////////////////////////////// + // ChipWhisperer CW310/305 Capture Board Interface // + ///////////////////////////////////////////////////// + // This is used to interface OpenTitan as a target with a capture board trough the ChipWhisperer + // 20-pin connector. This is used for SCA/FI experiments only. logic unused_inputs; - assign unused_inputs = manual_in_tio_clkout ^ manual_in_io_utx_debug; + % if target["name"] == "cw305": + assign unused_inputs = manual_in_io_clkout ^ manual_in_io_trigger ^ manual_in_io_utx_debug; + % else: + assign unused_inputs = manual_in_io_clkout ^ manual_in_io_trigger; + % endif - // Clock output to capture board. - assign manual_out_tio_clkout = manual_in_io_clk; - assign manual_oe_tio_clkout = 1'b1; + // Synchronous clock output to capture board. + assign manual_out_io_clkout = manual_in_io_clk; + assign manual_oe_io_clkout = 1'b1; + // Capture trigger. + // We use the clkmgr_aon_idle signal of the IP of interest to form a precise capture trigger. + // GPIO[11:9] is used for selecting the IP of interest. The encoding is as follows (see + // hint_names_e enum in clkmgr_pkg.sv for details). + // + // IP - GPIO[11:9] - Index for clkmgr_aon_idle + // ------------------------------------------------------------ + // AES - 000 - 0 + // HMAC - 001 - 1 + // KMAC - 010 - 2 - not implemented on CW305 + // OTBN (IO_DIV4) - 011 - 3 - not implemented on CW305 + // OTBN - 100 - 4 - not implemented on CW305 + // + // In addition, GPIO8 is used for gating the capture trigger in software. + // Note that GPIO[11:8] are connected to LED[3:0] on the CW310. + // On the CW305, GPIO[9,8] are connected to LED[5,7]. + + clkmgr_pkg::hint_names_e trigger_sel; + % if target["name"] == "cw305": + assign trigger_sel = mio_out[MioOutGpioGpio9] ? clkmgr_pkg::HintMainHmac : + clkmgr_pkg::HintMainAes; + % else: + always_comb begin : trigger_sel_mux + unique case ({mio_out[MioOutGpioGpio11], mio_out[MioOutGpioGpio10], mio_out[MioOutGpioGpio9]}) + 3'b000: trigger_sel = clkmgr_pkg::HintMainAes; + 3'b001: trigger_sel = clkmgr_pkg::HintMainHmac; + 3'b010: trigger_sel = clkmgr_pkg::HintMainKmac; + 3'b011: trigger_sel = clkmgr_pkg::HintIoDiv4Otbn; + 3'b100: trigger_sel = clkmgr_pkg::HintMainOtbn; + default: trigger_sel = clkmgr_pkg::HintMainAes; + endcase; + end + % endif + logic trigger, trigger_oe; + assign trigger = mio_out[MioOutGpioGpio8] & ~top_${top["name"]}.clkmgr_aon_idle[trigger_sel]; + assign trigger_oe = mio_oe[MioOutGpioGpio8]; + + // Synchronize trigger to manual_in_io_clk. + prim_flop_2sync #( + .Width ( 2 ) + ) u_sync_trigger ( + .clk_i ( manual_in_io_clk ), + .rst_ni ( manual_in_por_n ), + .d_i ( {trigger, trigger_oe} ), + .q_o ( {manual_out_io_trigger, manual_oe_io_trigger} ) + ); % endif ## This separate UART debugging output is needed for the CW305 only. % if target["name"] == "cw305": @@ -1216,7 +1236,6 @@ // UART Tx for debugging. The UART itself is connected to the capture board. assign manual_out_io_utx_debug = top_${top["name"]}.cio_uart0_tx_d2p; assign manual_oe_io_utx_debug = 1'b1; - % endif endmodule : chip_${top["name"]}_${target["name"]}